我在带有部分回发的更新面板中动态添加控件时遇到问题。我已经阅读了许多关于动态控件的文章,并且我了解如何使用回发添加和维护它们,但大多数信息并不适用,并且不适用于部分回发。我找不到任何有关使用 UpdatePanels 添加和维护它们的有用信息。如果可能的话,我想在不创建 Web 服务的情况下执行此操作。有没有人对一些有用的信息有任何想法或参考?
3 回答
我认为,对于 asp.net 程序员来说,这是常见的陷阱之一,但是当你知道发生了什么时,实际上并不难做到(永远记住你的视图状态!)。
下面的一段代码解释了如何做。这是一个简单的页面,用户可以在其中单击菜单,该菜单将触发将用户控件添加到更新面板内的页面的操作。
(这段代码是从这里借来的,并且有更多关于这个主题的信息)
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="SampleMenu1.aspx.cs" Inherits="SampleMenuPage1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Sample Menu</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Menu ID="Menu1" runat="server" OnMenuItemClick="Menu1_MenuItemClick">
<Items>
<asp:MenuItem Text="File">
<asp:MenuItem Text="Load Control1"></asp:MenuItem>
<asp:MenuItem Text="Load Control2"></asp:MenuItem>
<asp:MenuItem Text="Load Control3"></asp:MenuItem>
</asp:MenuItem>
</Items>
</asp:Menu>
<br />
<br />
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Menu1" />
</Triggers>
</asp:UpdatePanel>
</form>
</body>
</html>
和
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class PlainSampleMenuPage : System.Web.UI.Page
{
private const string BASE_PATH = "~/DynamicControlLoading/";
private string LastLoadedControl
{
get
{
return ViewState["LastLoaded"] as string;
}
set
{
ViewState["LastLoaded"] = value;
}
}
private void LoadUserControl()
{
string controlPath = LastLoadedControl;
if (!string.IsNullOrEmpty(controlPath))
{
PlaceHolder1.Controls.Clear();
UserControl uc = (UserControl)LoadControl(controlPath);
PlaceHolder1.Controls.Add(uc);
}
}
protected void Page_Load(object sender, EventArgs e)
{
LoadUserControl();
}
protected void Menu1_MenuItemClick(object sender, MenuEventArgs e)
{
MenuItem menu = e.Item;
string controlPath = string.Empty;
switch (menu.Text)
{
case "Load Control2":
controlPath = BASE_PATH + "SampleControl2.ascx";
break;
case "Load Control3":
controlPath = BASE_PATH + "SampleControl3.ascx";
break;
default:
controlPath = BASE_PATH + "SampleControl1.ascx";
break;
}
LastLoadedControl = controlPath;
LoadUserControl();
}
}
对于后面的代码。
基本上就是这样。您可以清楚地看到,当用户单击菜单项时,控件本身被动态添加到页面(在 updatePanel 内(实际上是在 updatePanel 内的 placeHolder 内),视图状态与LastLoadedControl一起保存,这将发送异步回发到服务器。
更多信息也可以在这里找到:
- http://aspnet.4guysfromrolla.com/articles/081402-1.aspx
- http://aspnet.4guysfromrolla.com/articles/082102-1.aspx
and of course on the website that holds the example code I used here.
I encountered the problem that using the method mentioned above, LoadUserControl() is called twice when handling an event. I've read through some other articles and would like to show you my modification:
1) Use LoadViewstate instead of Page_Load to load the user control:
protected override void LoadViewState(object savedState)
{
base.LoadViewState(savedState);
if (!string.IsNullOrEmpty(CurrentUserControl))
LoadDataTypeEditorControl(CurrentUserControl, panelFVE);
}
2) Don't forget to set the control id when loading the usercontrol:
private void LoadDataTypeEditorControl(string userControlName, Control containerControl)
{
using (UserControl myControl = (UserControl) LoadControl(userControlName))
{
containerControl.Controls.Clear();
string userControlID = userControlName.Split('.')[0];
myControl.ID = userControlID.Replace("/", "").Replace("~", "");
containerControl.Controls.Add(myControl);
}
this.CurrentUserControl = userControlName;
}
Try this:
Literal literal = new Literal();
literal.Text = "<script type='text/javascript' src='http://www.googleadservices.com/pagead/conversion.js'>";
UpdatePanel1.ContentTemplateContainer.Controls.Add(literal);
You can replace the content of literal with any HTML content you want...