积极答复者
为什么页面订阅静态事件在委托中无法更新页面信息

问题
-
CatalogService是一个静态类型,其中包括了数项静态事件。
一个Page实例订阅了CatalogService的某个事件,通过跟踪,委托成功加入到了事件的委托链,并有效引发。
此委托要更改页面的信息,文本的赋值一切正常,但是返回页面后没有任何变化,请教这是什么原因,如何解决?
事件委托类型的定义:
/// <summary>
/// 用于目录服务事件的委托类型
/// </summary>
/// <param name="sender">事件源对象</param>
/// <param name="e">目录服务事件参数对象</param>
public delegate void CatalogServiceEventHandler(object sender, CatalogServiceEventArgs e);
在CatalogService中引发事件的方法:
/// <summary>
/// 引发组创建完成时事件
/// </summary>
/// <param name="e">目录服务事件参数对象</param>
private static void OnGroupCreated(CatalogServiceEventArgs e)
{
CatalogServiceEventHandler temp;
if (null != (temp = (CatalogServiceEventHandler)m_EventTable["GroupCreated"]))
{
temp(null, e);
}
}
Page实例中订阅事件的代码:
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
CatalogService.GroupCreated += new CatalogServiceEventHandler(AfterCreated);
}
}
委托方法
public void AfterCreated(object sender, CatalogServiceEventArgs e)
{
//此委托要更改页面的信息,文本的赋值一切正常,但是返回页面后没有任何变化
this.Literal1.Text ="Group ID=" + e.CurrentGroupID + " created from CatalogService";
}- 已编辑 江天皓月 2009年8月15日 5:03
答案
-
您好,这个需要说到页面的生命周期。
当客户端发出请求时,webserver会创建一个与之对应的实例来处理。当网页执行完page_load方法后,重新回到客户端时,该实例已经完成它的使命了。
在您的代码中,将其与静态类事件绑定,那它还不会加到垃圾回收中,因此当事件被触发时,这个实例会进行相应的方法调用,可惜已传递不到客户端了。
这个实例将不会再次被使用。
当客户端再次发出请求时又会新创建一个实例,而不是上次绑定事件的实例。
每次请求都会创建新的HttpApplication实例,而这个实例也确实与您的静态类在同一进程,可惜HttpApplication不与客户端在同一进程中。- 已标记为答案 江天皓月 2009年8月15日 14:10
全部回复
-
你这是开发自定义控件吗?
我们一般都用普通委托和事件 很少用静态事件
因为要处理事关全局的关键变化,所以想采用静态事件以实现进程内的事件广播,这里没有特别的控件,只是设计了一个包含静态事件上下文的静态类型CatalogService。
以下是CatalogService中一个事件相关的代码
/// <summary> /// 目录组创建完成时的事件 /// </summary> public static event CatalogServiceEventHandler GroupCreated { add { lock (m_EventTable) { AddHandlerSafiely("GroupCreated", value); } } remove { lock (m_EventTable) { m_EventTable["GroupCreated"] = (CatalogServiceEventHandler)m_EventTable["GroupCreated"] - value; } } } /// <summary> /// 安全地添加委托方法 /// </summary> /// <param name="dictKey">委托字典中的键名</param> /// <param name="value">委托实例</param> private static void AddHandlerSafiely(string dictKey, CatalogServiceEventHandler value) { //如果已存在相同的委托进行覆盖 CatalogServiceEventHandler temp = (CatalogServiceEventHandler)m_EventTable[dictKey]; if (temp != null) { foreach (CatalogServiceEventHandler dd in temp.GetInvocationList()) { if (dd.Method == value.Method) { //从委托链中删除旧版本 temp -= dd; m_EventTable[dictKey] = temp; } } } //将新委托加入到委托链 m_EventTable[dictKey] = (CatalogServiceEventHandler)m_EventTable[dictKey] + value; }
-
楼主,您好,
这么设计在webform中是不可行的。这相当于从服务端主动发送信息给客户端。
http的协议是面向非连接的。您的代码设计只是将事件发送给了一个再也不会被用到的网页实例。
这是不会回写到客户端的。在winform中可以这么设计,因为是在同一进程内。webform是客户端和服务器端两个进程,还是跨机器的。
webform只能通过定时向服务器获取信息。
我还有一些不理解,“webform是客户端和服务器端两个进程,还是跨机器的”,页面提交到服务器时,虽然每个请求的处理是一个线程,不过一个Site应该是一个进程,因此才有HttpApplication对象吧?
另外,我也跟踪到了委托的代码有被执行,这要怎么解释才好?- 已编辑 江天皓月 2009年8月15日 13:45 还有不明白的
-
您好,这个需要说到页面的生命周期。
当客户端发出请求时,webserver会创建一个与之对应的实例来处理。当网页执行完page_load方法后,重新回到客户端时,该实例已经完成它的使命了。
在您的代码中,将其与静态类事件绑定,那它还不会加到垃圾回收中,因此当事件被触发时,这个实例会进行相应的方法调用,可惜已传递不到客户端了。
这个实例将不会再次被使用。
当客户端再次发出请求时又会新创建一个实例,而不是上次绑定事件的实例。
每次请求都会创建新的HttpApplication实例,而这个实例也确实与您的静态类在同一进程,可惜HttpApplication不与客户端在同一进程中。- 已标记为答案 江天皓月 2009年8月15日 14:10