none
请教取消事件的问题 RRS feed

  • 问题

  • CancelEventArgs的Cancel属性设为true的话表示取消事件,请问“取消”的具体含义是什么?比如有如下代码:
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    
    namespace Leo_CShape_001
    {
        class MyMessage
        {
            public delegate void MyEventHandler(object sender, CancelEventArgs cea);
            public event MyEventHandler Change;
            private string msg;
    
            public MyMessage(string message)
            {
                this.msg = message;
            }
    
            public string Message
            {
                get
                {
                    return msg;
                }
                set
                {
                    msg = value;
                }
            }
    
            public void ChangeMessage(CancelEventArgs cea)
            {
                OnChange(cea);
            }
    
            protected virtual void OnChange(CancelEventArgs cea)
            {
                if (Change != null)
                {
                    MyEventHandler handler = Change;
                    handler(this, cea);
                }
            }
        }
    
        class MessageAccess
        {
            public MessageAccess(MyMessage msg)
            {
                msg.Change += new MyMessage.MyEventHandler(Message_Change);
            }
    
            private void Message_Change(object sender, CancelEventArgs cea)
            {
                Random r = new Random();
                if (r.Next(11) % 2 == 0)
                {
                    cea.Cancel = true;
                }
                else
                {
                    cea.Cancel = false;
                }
            }
        }
    
        class Program
        {
            static void Main(string[] args)
            {
                MyMessage msg = new MyMessage("abc");
                MessageAccess ma = new MessageAccess(msg);
                msg.ChangeMessage(new CancelEventArgs());
                Console.WriteLine(msg.Message);
                Console.ReadLine();
            }
        }
    }
    
    在执行cea.Cancel = true后,CLR到底做了什么呢;还是说只是给了个flag,根据它的值在Main方法做不同的事?谢谢。
    2009年9月11日 15:34

答案

  • 您好,需要将
    protected virtual void OnChange(CancelEventArgs cea)
            {
                if (Change != null)
                {
                    MyEventHandler handler = Change;
                    handler(this, cea);
                }
            }

    改为:

    protected virtual void OnChange(CancelEventArgs cea)
            {
                if (Change != null)
                {
                    MyEventHandler handler = Change;
                    handler(this, cea); //调用订阅者的方法
                    if (cea.Cancel)
                    {
                         //在这里处理Cancel等于True的情况, cea.Cancel的值已由订阅者修改完毕了。
                    } 
                    else
                    { 
                         //在这里处理Cancel等于false
                    }
                    //e.Cancel的真假值是通过订阅者修改的。
                    //事件发布者(您的代码中是MyMessage),而订阅者是(您的代码中是MessageAccess)
                    //您一直有疑问在哪里控制,实际上是在发布者,而订阅者只需修改一个属性值,然后发布者会根据这个值来做处理,winform  中的原理相同!
                   //WinForm发布了一个事件叫Closing,而我们在开发是实际上是订阅者,只是付了一个值,WinForm会在自己的机制中来处理这个值,就如同上面我增加的这段代码。
                }
            }
    希望有帮助!
    • 已标记为答案 CatLeo 2009年9月12日 11:19
    2009年9月12日 6:18
  • 你好!
         关键的实现是CancelEventHandler委托,而CancelEventHandler只是起到包装一些参数数据的作用,你自己的委托使用这个类做参数也不能实现取消时间!CLR会把声明为CancelEventHandler的事件看成是可取消的,然后根据CancelEventHandler.Cancel的值来”通知“操作系统采取怎样的行动!
    周雪峰
    • 已标记为答案 CatLeo 2009年9月12日 11:19
    2009年9月12日 6:51
    版主

全部回复

  • 你好!
    我不知道你是什么方面的
    我是web的
    在我所理解控件机制的Cancel = true 后 做了if(!e.cancel){更改函数}  else{调用其他函数}
    2009年9月11日 15:46
  • VS2008的一段代码演示了使用 CancelEventArgsCancelEventHandler 来处理 FormClosing 事件的过程:
    // Call this method from the constructor of your form
        private void OtherInitialize() {
           this.Closing += new CancelEventHandler(this.Form1_Closing);
           // Exchange commented line and note the difference.
           this.isDataSaved = true;
           //this.isDataSaved = false;
        }
    
        private void Form1_Closing(Object sender, CancelEventArgs e) {
           if (!isDataSaved) {
              e.Cancel = true;
              MessageBox.Show("You must save first.");
           }
           else {
              e.Cancel = false;
              MessageBox.Show("Goodbye.");
           }
        }
    请问.Net是在什么地方判断Cancel的值并做相应操作的呢?如果自己定义的事件想达到类似效果,又该怎么做呢?
    2009年9月11日 16:09
  • http://hi.baidu.com/jywb_pub/blog/item/0377cc881b95d890a4c27285.html 参考一下
    如果自定义的话 继承委托类 再定义个bool属性就可以了
    这些是自定义控件方面的
    我对winform一窍不通 呵呵 等高人
    2009年9月11日 16:34
  • 刚又看了下MSDN里对CancelEventArgs的描述,注意到它的作用是“为可取消的事件提供数据”。这样的事件在实际中好理解,比如关闭窗口之类的。但在代码中什么样的事件才是可取消的呢?MSDN里还说“可取消的事件由某个组件在其即将执行某项可取消的操作时引发”,那么可取消的操作在代码中又是如何表示的呢?

    2009年9月11日 16:41
  • 请你明天再来看吧 现在高人都睡觉了 明天会有很多人解释的
    2009年9月11日 16:51
  • 这个事件只是传递一个布尔值而已,怎么处理这个值由事件的处理程序决定,没有一定的规定。比如我可以用这个来传递一个复选框的状态,当然从软件设计的角度来说,这样的代码可读性不高,我应该创建自己的事件类型来让代码更加便于阅读。

    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful.
    Visual C++ MVP
    2009年9月11日 17:28
    版主
  • 因为刚接触C#不久,可能概念有点模糊。我的理解是Form1_Closing(Object sender, CancelEventArgs e)就是事件处理程序,如果没错的话它的代码里只是给Cancel设了值而已啊,为什么这样就避免了窗体关闭呢?
    2009年9月11日 17:57
  • 那是因为Form类在触发事件之后有根据结果改变流程。

    The following is signature, not part of post
    Please mark the post answered your question as the answer, and mark other helpful posts as helpful.
    Visual C++ MVP
    2009年9月11日 18:31
    版主
  • 你好,Form1_Closing,再.NET中,通常有两种写法,一种是ing结尾,一种是ed结尾。从字面上我们可以知道,事件触发的临界点不一样。这里,Closing表示触发了这个时间,但是还没有执行Close动作,用户可以修改是否反悔不关闭,或者关闭之前提示用户先保存资料,如果没有保存就不关闭等等。Cancel只是一个属性,用来代表是否真的需要关闭,如果为True就Ruturn了,不会执行关闭代码。
    jon.valett@gmail.com
    2009年9月12日 2:15
    版主
  • 多谢指导。那么请问下比如最上面那个Message_Change中,想实现把Cancel设为true就直接返回,不改变Message内容该怎么写呢?我是指不在Message_Change里显示写if(e.Cancel) do something;else do something。而像Form1_Closing一样只要Cancel设为true就不关闭窗体。会是在ChangeMessage方法里根据Cancel的值做某些操作?还是说Closing事件其实还注册了其它事件处理函数,它们会根据Cancel的值真正做是否关闭窗体的工作?但是我好像记得用+=注册多个事件处理函数的话并不能保证它们的调用顺序,如果真是根据Form1_Closing对Cancel设值的话怎么确定Form1_Closing最先调用呢?
    2009年9月12日 2:45
  • 您好,需要将
    protected virtual void OnChange(CancelEventArgs cea)
            {
                if (Change != null)
                {
                    MyEventHandler handler = Change;
                    handler(this, cea);
                }
            }

    改为:

    protected virtual void OnChange(CancelEventArgs cea)
            {
                if (Change != null)
                {
                    MyEventHandler handler = Change;
                    handler(this, cea); //调用订阅者的方法
                    if (cea.Cancel)
                    {
                         //在这里处理Cancel等于True的情况, cea.Cancel的值已由订阅者修改完毕了。
                    } 
                    else
                    { 
                         //在这里处理Cancel等于false
                    }
                    //e.Cancel的真假值是通过订阅者修改的。
                    //事件发布者(您的代码中是MyMessage),而订阅者是(您的代码中是MessageAccess)
                    //您一直有疑问在哪里控制,实际上是在发布者,而订阅者只需修改一个属性值,然后发布者会根据这个值来做处理,winform  中的原理相同!
                   //WinForm发布了一个事件叫Closing,而我们在开发是实际上是订阅者,只是付了一个值,WinForm会在自己的机制中来处理这个值,就如同上面我增加的这段代码。
                }
            }
    希望有帮助!
    • 已标记为答案 CatLeo 2009年9月12日 11:19
    2009年9月12日 6:18
  • 你好!
         关键的实现是CancelEventHandler委托,而CancelEventHandler只是起到包装一些参数数据的作用,你自己的委托使用这个类做参数也不能实现取消时间!CLR会把声明为CancelEventHandler的事件看成是可取消的,然后根据CancelEventHandler.Cancel的值来”通知“操作系统采取怎样的行动!
    周雪峰
    • 已标记为答案 CatLeo 2009年9月12日 11:19
    2009年9月12日 6:51
    版主
  • 感谢指导,终于弄明白了。另外再请问下,按照如上所说,针对自己定义的非系统标准事件,是否实际上用CancelEventHandler和自己定义委托效果相同,因为操作系统都不知道怎样取消操作,而应该像Jiyuan所演示那样自己处理?
    2009年9月12日 11:20
  • 感谢指导,终于弄明白了。另外再请问下,按照如上所说,针对自己定义的非系统标准事件,是否实际上用CancelEventHandler和自己定义委托效果相同,因为操作系统都不知道怎样取消操作,而应该像Jiyuan所演示那样自己处理?

    您好,事件是依托于委托的,建议参考一些关于委托和事件的资料。
    其实CancelEventHandler委托只不过是微软帮我们定义好的,目的为了给我们指明一些使用.Net Framework的方法。
    如果您正在开发事件发布,那么就相当于您站在设计WinForm类的角度,对于自己发布的事件,只能由自己来控制和实现。除非您开发的事件类又是订阅于.Net发布的事件。
    2009年9月12日 12:02
  • 你需要直接使用CancelEventHandler来声明事件!

    周雪峰
    2009年9月12日 14:03
    版主