在回发中保留用户控件(ASCX)EventHandler对象

时间:2016-03-16 15:35:36

标签: c# asp.net webforms postback ascx

假设您有用户控件(ASCX):

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="Test.ascx.cs" 
    Inherits="WebApplication1.Test" %>
<asp:Button ID="test" runat="server" OnClick="test_Click" Text="test" />

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class Test : System.Web.UI.UserControl
    {        
        public event EventHandler Method1;

        public EventHandler Method2
        {
            get { return (EventHandler)Session[this.ClientID + "|Method2"]; }
            set { Session[this.ClientID + "|Method2"] = value; }
        }

        public EventHandler Method3
        {
            get { return (EventHandler)ViewState["Method3"]; }
            set { ViewState["Method3"] = value; }
        }

        protected void test_Click(object sender, EventArgs e)
        {
            if (Method1 != null)
                Method1(this, e);

            if (Method2 != null)
                Method2(this, e);

            if (Method3 != null)
                Method3(this, e);
        }
    }
}

你有一个页面可以放置UserControl:

<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.Master" 
    AutoEventWireup="true" CodeBehind="Default.aspx.cs" 
    Inherits="WebApplication1._Default" %>
<%@ Register Src="~/Test.ascx" TagName="Test" TagPrefix="uc1" %>

<asp:Content runat="server" ID="BodyContent" ContentPlaceHolderID="MainContent">
    <uc1:Test ID="TestControl" runat="server" />
    <asp:Label ID="Result" runat="server" Text="Test" />
</asp:Content>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace WebApplication1
{
    public partial class _Default : Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //Uncomment each one to observe their behavior

            //Will never trigger(unless reset on each postback)
            //if (!IsPostBack) TestControl.Method1 += new EventHandler(Test);

            //Will trigger(the code will run) but makes no change to the parent page
            //if (!IsPostBack) TestControl.Method2 += new EventHandler(Test);

            /*
            Will fail because it can't serialize the "EventHandler" object
            You can play around by changing this to a delegate type 
            and making that serializable, but that fails as well  
            */
            //if (!IsPostBack) TestControl.Method3 += new EventHandler(Test);
        }
        protected void Test(object sender, EventArgs e)
        {
            Result.Text = Guid.NewGuid().ToString();
        }
    }
}

但是对于这个给定的用户控件,我们想要定义一个事件来捕获按钮的点击,并触发用户控件父母选择的事件。另外由于本例范围之外的要求,我们只想设置&#34; MethodX&#34;的值。 EventHandler一次,即不在每个Postback上重新创建控件/属性(在此示例中,我通过仅在页面加载上设置一次事件来演示此概念)。

如何实现这一目标?我尝试过的所有三种方法都以自己独特的方式失败了......到目前为止,我还没有找到与事件持续性相关的类似问题,大多数帖子都涉及变量/对象持久性(&#34) ;使用ViewState&#34;或其他各种持久化非事件对象的方法,请参阅link)或简单地指导用户在每个Postback(包括相关属性)上重新创建控件&#34; ,见link

任何反馈或见解都会有所帮助,尤其令我感到困惑的是&#34; Method2&#34;的行为,我认为我对页面生命周期的理解不足以理解为什么发生了。

1 个答案:

答案 0 :(得分:2)

您需要在加载事件之前注册事件(尝试初始化)。在init和load事件之间发生Click事件触发。

更新:抱歉,您在Load和LoadComplete之间引发了右键单击事件。

更新:我认为我找到了你需要的东西,令人失望的是,它不可能是你想要的。非静态方法的实例委托强烈依赖于方法类的实例。每个请求,页面实例都被创建,当请求结束时,它被处理掉。页面不是单例实例。这就是为什么,即使你将处理程序存储在会话中,它也无法重用,因为它试图从已处理的实例调用一个方法。

这是一篇关于事件和代表如何运作的好文章:http://csharpindepth.com/Articles/Chapter2/Events.aspx

最重要的部分是:

  

[..]任何特定委托实例中数据的关键点是委托引用的方法,以及在(目标)上调用方法的引用。对于静态方法,不需要目标。

target 是您创建的第一刻页面的页面/用户控件实例。当您进行回发时,页面/ usercontrol实例已更改,但您的持久化处理程序的目标未更改。