委托与事件的区别,一次性讲清

TextCtrl.xaml

  <Grid>
        <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center" Height="68">
            <Button Width="100" Margin="10" Content="清除" x:Name="btnClear"/>
            <Button Width="100" Margin="10" Content="恢复" x:Name="btnRecall"/>
        </StackPanel>
    </Grid>

TextCtrl.xaml.cs

  public partial class TextCtrl : UserControl
    {
        public TextCtrl()
        {
            InitializeComponent();         
            this.btnClear.Click +=this.clearClick;
            this.btnRecall.Click += this.recalClick;
        }
        public event Action<string,string> clearEvent;
        public event Action<string,string> recallEvent;
        public Action clear_delegate;
        public Action recall_delegate;

        private void clearClick(object sender, RoutedEventArgs e)
        {
            if (clearEvent != null) { clearEvent("clear", "event"); }//没有Invoke()方法
            if (clear_delegate != null) { clear_delegate.Invoke(); }//有Invoke()方法
        }

        private void recalClick(object sender, RoutedEventArgs e)
        {
            if (recallEvent != null) { recallEvent("recall","event"); }//没有Invoke()方法
            if (recall_delegate != null) { recall_delegate.Invoke(); }//有Invoke()方法
        }
      
    }

MainWindow.xaml

<Grid>
        <StackPanel Orientation="Vertical" >         
            <TextBox Width="200" Height="45" HorizontalAlignment="left" Margin="10" x:Name="txtBox" />
            <local:TextCtrl HorizontalAlignment="Left" Margin="10 0 10 0"  x:Name="textCtrl"/>
            <TextBlock x:Name="txtBlock" Height="Auto" Width="Auto" Foreground="Red" FontSize="14"/>
        </StackPanel>
    </Grid>

MainWindwo.xaml.cs

  public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            this.textCtrl.clearEvent += TextCtrl_clearEvent;
            this.textCtrl.recallEvent += TextCtrl_recallEvent;
            // this.textCtrl.clearEvent += new Action<string,string> (TextCtrl_clearEvent);//也可以这么写
            // this.textCtrl.recallEvent +=new Action<string,string>( TextCtrl_recallEvent);//也可以这么写
            // this.textCtrl.clearEvent = TextCtrl_clearEvent; //报错
            // this.textCtrl.recallEvent = TextCtrl_recallEvent; //报错


            this.textCtrl.clear_delegate += textBlockClear;
            this.textCtrl.recall_delegate += textBlockRecall;
            // this.textCtrl.clear_delegate += new Action(textBlockClear);//也可以这么写
            //this.textCtrl.recall_delegate += new Action(textBlockRecall);//也可以这么写
            // this.textCtrl.clear_delegate = textBlockClear;//不报错
            // this.textCtrl.recall_delegate = textBlockRecall;//不报错

        }
        private string text;
        public string Text 
          { get
            { 
               return text;
            }
           set{
                text = value;
             } 
        }

        private void TextCtrl_recallEvent(string arg1, string arg2)
        {
            txtBox.Text = Text;
        }

        private void TextCtrl_clearEvent(string arg1, string arg2)
        {         
            Text = txtBox.Text;
            txtBox.Clear();
        }
        private void textBlockClear()
        {
            txtBlock.Text = "Clear";
        }

        private void textBlockRecall()
        {
            txtBlock.Text = "Recall";
        }
    }

event修饰后,可以在xaml上写这个自定义事件

  <local:TextCtrl HorizontalAlignment="Left" Margin="10 0 10 0"  x:Name="textCtrl" clearEvent="TextCtrl_clearEvent"  recallEvent="TextCtrl_recallEvent"/>

运行效果:

讲解部分:

一、委托概念

1、概念:Delegate(委托、代理...):委托其实一种程序特性,它特的特点就在于,委托是用来表示方法的。换句话说委托是方法的代表、方法的指针。

int age=10;age其实就是10的代表。

Course myCourse = new Course();   myCourse是一个特定对象的代表。

委托类型  委托变量=具体方法(可以是1个,也可以是多个)。委托就方法的变量。

2、为什么要使用委托?

生活中想象一下,比如我们做一件事情,但是我们自己无法直接去完成。但是我们通过别人可以帮我们完成。

    我--->其他人(委托)--->做事情

   通过刚才的比较,我们发现,前面age、myCourse等代表的都是某种“静态数据”。

   委托代表的是“行为”,就是方法。

软件开发中,我们也会遇到类似情况,那就是我们本身想调用一个行为(方法)但是这个方法因为再不同的对象中,

我们可能直接调用不了,这时候就可以使用委托。

  正常情况下:A对象中,创建了B对象,这时候,如果B对象中有一个公共行为C,那么我们在A中是能调用的。

 class A
{

      B b=new B();

     void MyMethod()
     {
             b.C();
    }

     void NewMethod(){}
}

问题:如果B想调用A中的行为NewMethod是否可以?当然不行!但是通过委托是可以的。


二、委托的基本使用

1. 声明委托(定义方法的原型:方法的返回值类型、方法的参数类型和个数)

2.根据委托编写具体方法

3. 创建委托变量(委托是引用类型)

4. 将委托变量和一个或多个符合委托定义的具体的方法关联。

5. 通过委托变量使用具体的方法(不是直接使用方法)

结论:通过委托变量,可以轻松的调用它所关联的具体方法。

扩展:如果我们给委托变量,同时关联了多个方法,当我们使用委托变量的时候,方法会按照你关联的顺序依次调用。

          以上就是我们常说的“多路委托或叫做多播委托”。

好处:我们不仅能动态的增加委托对方法的关联,还可以动态的移除方法的关联。

三、委托的实战应用(一):在多窗体通信中的使用

1、在主窗体A中,创建了若干子窗体B的对象。

     现在B窗体需要调用A中的一个方法。正常情况是不行的。但是可以通过委托实现。


2、提示:我们使用委托完成任务的时候,委托变量在哪里定义的技巧是:在哪里使用,就在哪里定义!(谁使用谁创建)

     委托变量和具体方法的关联,通常是分开的。一般就是在具体方法定义的地方,进行关联。


总结: B1->A     B2->A   B3->A

扩展:通过委托如何实现消息的广播?

         在哪里接收消息,就把接收消息的方法写到哪里!这里是B窗体。

         
四、委托的实战应用(二):解决在容器嵌入窗体时的切换问题

五、事件Event(和委托比较)

随便找一个: this.btnCreateChildForm.Click += new System.EventHandler(this.btnCreateChildForm_Click);

public event EventHandler Click

public delegate void EventHandler(object sender, EventArgs e);

通过观察按钮的事件,发现了事件其实是委托的进一步包装。

定义事件:(直接看代码)案例中,我们实现和前面一样的功能,但是这次通过事件来实现。

事件概念:事件其实是对象对外界信息的刺激,产生的一种消息响应机制。

本质:事件其实是委托的进一步包装。

事件的参与者:

【1】发送者(sender):就是对象本身,当时本身信息状态变化的时候,触发一个事件,并通知所有的接受者接收。

 passMsgEvent(this.txtSendMsg.Text, this.Text);

【2】接受者(Receiver):就是事件的处理者,在事件发送者触发后,会自动执行的这段代码。

       private void ReceiveMsg(string msg, string childName)
        {
            this.txtContent.Text += $"来自:{childName} 的消息:{msg}\r\n";
        }

事件和委托对比不同点:

第一、事件无法直接赋值,比如事件=null;会出现编译错误,而委托可以。

           好处:避免用户对事件直接操作,比如Click事件,如果允许Click=null,会把底层代码清除!可以起到保护。

                     委托相对太“开放”。

第二、event对象没有invoke()方法,只能通过使用括号的方式来运行。


委托和事件的选择:

第一、正常解决问题,你使用委托和事件没有什么本质区别。所以,我们建议是使用委托。

第二、如果我们做控件二次开发,扩展控件的事件的时候,那必须用事件。

猜你喜欢

转载自blog.csdn.net/qq_41617901/article/details/110297691
今日推荐