通过一个WPF实例进一步理解委托和事件

时间:2015-08-26 17:59:56   收藏:0   阅读:5309

在前写过“浅谈C#中的委托”和“浅谈C#中的事件”两篇博客,内容有些抽象,似乎难以说明委托和事件的关系。

今天通过一个小程序来进一步说明二者的使用及联系。

首先新建一个WPF应用程序,取名TestDelegateAndEvent。
在.xmal中加入四个按钮,并添加Window_Loaded事件。
技术分享
代码如下:

<Window x:Class="TestDelegateAndEvent.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded"> 
    <Grid> 
        <Button Content="执行委托" Height="39" HorizontalAlignment="Left" Margin="128,53,0,0" Name="button1" VerticalAlignment="Top" Width="254" Click="button1_Click" /> 
        <Button Content="干扰委托" Height="39" HorizontalAlignment="Left" Margin="128,118,0,0" Name="button2" VerticalAlignment="Top" Width="254" Click="button2_Click" /> 
        <Button Content="执行事件" Height="39" HorizontalAlignment="Left" Margin="128,181,0,0" Name="button3" VerticalAlignment="Top" Width="254" /> 
        <Button Content="干扰事件" Height="39" HorizontalAlignment="Left" Margin="128,241,0,0" Name="button4" VerticalAlignment="Top" Width="254" /> 
    </Grid> 
</Window>

接下来是编写.cs代码:
定义了一个委托,并对委托进行了挂载函数

public class Test
{
    public delegate void MyDelegate(); 
    //创建一个委托实例 
    public MyDelegate myDel; 

}

Test test = new Test();
public MainWindow() 
{
     InitializeComponent(); 
} 
//方法A 
public void Fun_A() 
{ 
    MessageBox.Show("A 方法触发了"); 
} 
//方法B 
public void Fun_B() 
{ 
    MessageBox.Show("B 方法触发了"); 
} 
//方法C 
public void Fun_C() 
{ 
    MessageBox.Show("C 方法触发了"); 
} 

private void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    //注册委托(挂载方法) 
    test.myDel += Fun_A; 
    test.myDel += Fun_B; 

} 
private void button1_Click(object sender, RoutedEventArgs e)
 { 
     test.myDel(); 
 } 
 private void button2_Click(object sender, RoutedEventArgs e)
 { 
      test.myDel = null; 
      test.myDel += Fun_C; 
 } 

运行以上代码,点击执行委托,弹出了两个messagebox。点击干扰委托,然后再点击执行委托,就弹出了一个messagebox,即只有”c方法被触发了”。我们可以看到,一切都是由myDel = null引起的。

委托本质就是一个类, 它包含一对有用的字段,第一个字段是存放该对象的引用,第二个字段存放一个方法的指针,所以我们可以把委托理解成一个指向函数的指针,当一个方法作为参数 赋值给一个委托的时候,该委托就指向了该方法的首地址,即方法名,所以当我们给委托注册A,B两个方法,该委托就同时指向了A,B两个方法的首地址,但这 是又突然给委托赋值了,且赋值了一个null对象,注意这里用的是赋值符号[=],这就是说让该委托清除原有的指针指向,此时指向一个null,之后又给 委托注册了C方法,所以此时委托即指向null,又指向了C方法的首地址,这就是为什么运行时只会看到C方法被触发的原因了!

那就是说现在的委托变得不安全了,哪天一个项目中给委托注册了很多方法,但突然被干扰了下,前面的注册都失效了,那我们前面做的工作不是白做了,那有没有办法可以防止这种干扰呢??答案是当然有,相信聪明的你也应该猜到了,这时就是事件该上场的时候了。

我们对代码进行重写,加入了事件。
在Window_Loaded函数中加入代码:
test.EventMyDel += Fun_A;
test.EventMyDel += Fun_B;
当我们在Button4_Click中加入代码test.EventMyDel = null时,编译器会报错:
错误 CS0070: 事件“TestDelegateAndEvent.MainWindow.Test.EventMyDel”只能出现在 += 或 -= 的左边(从类型“TestDelegateAndEvent.MainWindow.Test”中使用时除外)。
这说明了在事件中允许使用 = 运算符进行订阅。

public class Test
{
    public delegate void MyDelegate(); 
    //创建一个委托实例 
    public MyDelegate myDel; 
    //声明一个事件
    public event MyDelegate EventMyDel;
    //事件触发机制(必须和事件在同一个类中) 外界无法直接用EventMyDel()来触发事件
    public void DoEventDel()
    {
        EventMyDel()
    }
}

Test test = new Test();
public MainWindow() 
{
     InitializeComponent(); 
} 
//方法A 
public void Fun_A() 
{ 
    MessageBox.Show("A 方法触发了"); 
} 
//方法B 
public void Fun_B() 
{ 
    MessageBox.Show("B 方法触发了"); 
} 
//方法C 
public void Fun_C() 
{ 
    MessageBox.Show("C 方法触发了"); 
} 

private void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    //注册委托(挂载方法) 
    test.myDel += Fun_A; 
    test.myDel += Fun_B; 
    test.EventMyDel += Fun_A;
    test.EventMyDel += Fun_B;

} 
private void button1_Click(object sender, RoutedEventArgs e)
 { 
     test.myDel(); 
 } 
 private void button2_Click(object sender, RoutedEventArgs e)
 { 
      test.myDel = null; 
      test.myDel += Fun_C; 
 } 
 private void button3_Click(object sender, RoutedEventArgs e) 
 { 
     test.DoEventMyDel(); 
 } 
 private void button4_Click(object sender, RoutedEventArgs e) 
 { 
     test.EventMyDel += null; 
     test.EventMyDel += Fun_C; 
}

通过上述代码可以看出,委托可以使用“=”,而事件不可以使用“=”。即事件是对委托的一种封装,也就像是属性与字段的关系。

此时需要特别注意一下上述的错误,如果不写Test类,即不进行封装。那么如果在与事件相关代码位于同一个类中的代码注册事件时,使用“=”是可以的,下面的代码就不会报错!!!
即:


    public delegate void MyDelegate(); 
    //创建一个委托实例 
    public MyDelegate myDel; 
    //声明一个事件
    public event MyDelegate EventMyDel;
    //事件触发机制(必须和事件在同一个类中) 外界无法直接用EventMyDel()来触发事件
    public void DoEventDel()
    {
        EventMyDel()
    }
public MainWindow() 
{
     InitializeComponent(); 
} 
//方法A 
public void Fun_A() 
{ 
    MessageBox.Show("A 方法触发了"); 
} 
//方法B 
public void Fun_B() 
{ 
    MessageBox.Show("B 方法触发了"); 
} 
//方法C 
public void Fun_C() 
{ 
    MessageBox.Show("C 方法触发了"); 
} 

private void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    //注册委托(挂载方法) 
    myDel += Fun_A; 
    myDel += Fun_B; 
    //注册事件
    EventMyDel += Fun_A;
    EventMyDel += Fun_B;

} 
private void button1_Click(object sender, RoutedEventArgs e)
 { 
     myDel(); 
 } 
 private void button2_Click(object sender, RoutedEventArgs e)
 { 
      myDel = null; 
      myDel += Fun_C; 
 } 
 private void button3_Click(object sender, RoutedEventArgs e) 
 { 
     DoEventMyDel(); 
 } 
 private void button4_Click(object sender, RoutedEventArgs e) 
 { 
     EventMyDel = null;//**不会报错** 
     EventMyDel += Fun_C; 
}

“`

版权声明:本文为博主原创文章,未经博主允许不得转载。

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!