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

时间:2014-03-10 14:20:38

标签: c# asp.net webforms

我遇到了以下问题:我有一个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也一直反应并重新加载其整个内容。

有人可以给我任何有关如何正确执行此操作的有用提示吗?

创建servercontrol就像这样:

//跟随在页面选项卡上的ComboBox / TabChanged上的OnLoad / IndexChanged中调用的函数

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

亚历山大指出我看了this,这是我的问题。我继续,使用此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进行必要的更改以使其像按钮一样工作?

1 个答案:

答案 0 :(得分:0)

这有效:

但是我不确定是否打算使servercontrol更新最近的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;
        }
    }
}