如何编写服务器控件以使其支持ASP中的部分回发?净WebForms

本文关键字:WebForms 服务器控件 何编写 ASP 支持 | 更新日期: 2023-09-27 17:49:23

我有以下问题:我有一个WebForms页面,其中包含一个列布局,在占位符ph1内重新加载自定义服务器控件时闪烁。

为了避免这种情况,我正在考虑改进我们的服务器控件来支持部分回发。我不太知道如何做到这一点。因此,当控件触发回发时,我只希望udp2更新其内容,而不是udp1对引发的回发做出反应。

我的页面结构是这样的:

<updatepanel id="udp1">
 <tree>
 </tree>
 <updatepanel id="udp2">
  <ContentTemplate>
   <div id="ph1" runat="server"></div> <!--- receives generated servercontrol's
  </ContentTemplate>
 </updatepanel>
</updatepanel>

到目前为止,我尝试使此工作没有成功,udp1总是反应良好,并重新加载其整个内容。

谁能给我一些有用的建议,告诉我如何正确地做这件事?

服务器控件的创建过程如下:

//下面的函数调用OnLoad/IndexChanged on ComboBox/TabChanged on Tabs on page

public void CreateControls()
{
 var dataItems = GetData();
 foreach(var data in dataItems)
 {
  var control = CreateServerControl(data); // typeof CustomServerControl
  control.ID = "generated"+data.Identifier.ToString();
  ph1.Controls.Add(control);
 }
}

是否有某种类型的接口,我必须在CustomServerControl上实现,以使该控件在下一个可用的UpdatePanel(但只有udp2,而不是upd1)内引发回发时更新

CustomServerControl中用于在客户端启动回发的代码:

var options = new PostBackOptions(this, "update"); 
// turns into javascript:__doPostBack('somerenderedid','update');
link.href = string.Format("javascript:{0};", this.Page.ClientScript.GetPostBackEventReference(options)); 

编辑1 :

正如Alexander指出的,我看过这个,这正是我的问题。我继续,用这个ServerControl:创建了一个示例项目,并把它放在Page

[ParseChildren(false)]
public class TestControl : WebControl
{
    protected override HtmlTextWriterTag TagKey
    {
        get { return HtmlTextWriterTag.A; }
    }
    protected override void OnPreRender(EventArgs e)
    {
        var pbo = new PostBackOptions(this, "update");
        this.Attributes.Add("href", string.Format("javascript:{0};", this.Page.ClientScript.GetPostBackEventReference(pbo)));
        base.OnPreRender(e);
    }
}
<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ Register TagPrefix="a" Namespace="NestedUpdatePanelTest"             Assembly="NestedUpdatePanelTest" %>
<!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 id="Head1" runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="frmMain" runat="server">
<asp:ScriptManager runat="server" EnablePartialRendering="true" ID="TheScriptManager" />
<asp:UpdatePanel ID="aupParent" runat="server" UpdateMode="Conditional">
    <ContentTemplate>
        <a:TestControl runat="server">outer</a:TestControl>
        <asp:Button ID="btnParent" runat="server" Text="Update the parent (and all childs of course)" />
        <%= "Parent panel last updated at:" + DateTime.Now.ToString( ) %>
        <asp:UpdatePanel ID="aupChild" runat="server" UpdateMode="Conditional">
            <ContentTemplate>
                <a:TestControl runat="server">inner</a:TestControl>
                <asp:Button ID="btnChild" runat="server" Text="Update only the child" />
                <%= "Child panel last updated at:" + DateTime.Now.ToString( ) %>
            </ContentTemplate>
        </asp:UpdatePanel>
    </ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>

按asp:Button元素完全是我想要的。但是,单击链接则不会。为了使TestControl像按钮一样工作,需要对它进行哪些必要的更改?

如何编写服务器控件以使其支持ASP中的部分回发?净WebForms

这行得通:

然而,我不确定是否这是打算的方式去做一个服务器控制更新最近的UpdatePanel?欢迎更正和反馈。否则我将把它标记为回答。

(我希望过去的我早点知道这件事)

[ParseChildren(false)]
public class TestControl : WebControl, IPostBackEventHandler
{
    protected override HtmlTextWriterTag TagKey
    {
        get { return HtmlTextWriterTag.A; }
    }
    protected override void OnPreRender(EventArgs e)
    {
        var pbo = new PostBackOptions(this, "update");
        this.Attributes.Add("href", string.Format("javascript:{0};", this.Page.ClientScript.GetPostBackEventReference(pbo)));
        ScriptManager.GetCurrent(this.Page).RegisterAsyncPostBackControl(this);
        base.OnPreRender(e);
    }
    // works when used in UpdatePanel.Triggers property.
    public event EventHandler SomeEvent;
    public void RaisePostBackEvent(string eventArgument)
    {
        var h = SomeEvent;
        if(h != null)
           h(this, EventArgs.Empty);
        UpdatePanel p;
        Control parent = this.Parent;
        while (parent != null)
        {
            p = parent as UpdatePanel;
            if (p != null)
            {
                p.Update();
                return;
            }
            parent = parent.Parent;
        }
    }
}