none
为什么页面订阅静态事件在委托中无法更新页面信息 RRS feed

  • 问题

  • 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日 4:05

答案

  • 您好,这个需要说到页面的生命周期。
    当客户端发出请求时,webserver会创建一个与之对应的实例来处理。当网页执行完page_load方法后,重新回到客户端时,该实例已经完成它的使命了。
    在您的代码中,将其与静态类事件绑定,那它还不会加到垃圾回收中,因此当事件被触发时,这个实例会进行相应的方法调用,可惜已传递不到客户端了。
    这个实例将不会再次被使用。

    当客户端再次发出请求时又会新创建一个实例,而不是上次绑定事件的实例。

    每次请求都会创建新的HttpApplication实例,而这个实例也确实与您的静态类在同一进程,可惜HttpApplication不与客户端在同一进程中。
    2009年8月15日 14:02
    版主

全部回复

  •      if (!IsPostBack)去掉试试看 
    你描述问题 太不清楚
     
    2009年8月15日 4:20
  • 因为静态事件的委托链是进程内可见的,所以这个if (!IsPostBack)块并不构成问题,只是在页面初次加载时添加订阅事件而已
    事件本身被处理成不重复添加已经存在的委托。除非进程重启,委托链中的委托不会消失。
    2009年8月15日 4:49
  • 你这是开发自定义控件吗?
    我们一般都用普通委托和事件 很少用静态事件

    2009年8月15日 7:17
  • 你这是开发自定义控件吗?
    我们一般都用普通委托和事件 很少用静态事件


    因为要处理事关全局的关键变化,所以想采用静态事件以实现进程内的事件广播,这里没有特别的控件,只是设计了一个包含静态事件上下文的静态类型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;
            }
    2009年8月15日 7:40
  • 楼主,您好,
    这么设计在webform中是不可行的。这相当于从服务端主动发送信息给客户端。
    http的协议是面向非连接的。您的代码设计只是将事件发送给了一个再也不会被用到的网页实例。
    这是不会回写到客户端的。在winform中可以这么设计,因为是在同一进程内。webform是客户端和服务器端两个进程,还是跨机器的。
    webform只能通过定时向服务器获取信息。
    2009年8月15日 13:18
    版主
  • 楼主,您好,
    这么设计在webform中是不可行的。这相当于从服务端主动发送信息给客户端。
    http的协议是面向非连接的。您的代码设计只是将事件发送给了一个再也不会被用到的网页实例。
    这是不会回写到客户端的。在winform中可以这么设计,因为是在同一进程内。webform是客户端和服务器端两个进程,还是跨机器的。
    webform只能通过定时向服务器获取信息。

    我还有一些不理解,“webform是客户端和服务器端两个进程,还是跨机器的”,页面提交到服务器时,虽然每个请求的处理是一个线程,不过一个Site应该是一个进程,因此才有HttpApplication对象吧?

    另外,我也跟踪到了委托的代码有被执行,这要怎么解释才好?
    • 已编辑 江天皓月 2009年8月15日 13:45 还有不明白的
    2009年8月15日 13:39
  • 您好,这个需要说到页面的生命周期。
    当客户端发出请求时,webserver会创建一个与之对应的实例来处理。当网页执行完page_load方法后,重新回到客户端时,该实例已经完成它的使命了。
    在您的代码中,将其与静态类事件绑定,那它还不会加到垃圾回收中,因此当事件被触发时,这个实例会进行相应的方法调用,可惜已传递不到客户端了。
    这个实例将不会再次被使用。

    当客户端再次发出请求时又会新创建一个实例,而不是上次绑定事件的实例。

    每次请求都会创建新的HttpApplication实例,而这个实例也确实与您的静态类在同一进程,可惜HttpApplication不与客户端在同一进程中。
    2009年8月15日 14:02
    版主
  • 十分感谢。
    2009年8月15日 14:11
  • 不客气,互相交流。:)

    2009年8月16日 4:46
    版主