C#委托和事件(WPF实现关闭子窗口B时触发A窗口事件)

     遇到一个问题,子窗口关闭时,主窗口如何知道子窗口关闭了,并执行相应的处理事件。为了解决这个问题查阅资料后可以用委托和事件来完成。

一、委托

1、委托:

       委托是安全封装方法的类型,类似于 C 和 C++ 中的函数指针。 与 C 函数指针不同的是,委托是面向对象的、类型安全的和可靠的。假如委托没有引用一个有效的方法,就不允许调用这个委托。

       委托是指向一个方法的指针,而且我们采用和调用方法一样的方式调用它。调用一个位委托时,运行时实际执行的是委托所引用的方法。可以动态的更改一个委托引用的方法,使调用一个委托的代码每次都运行一个不同的方法。

      委托(Delegate)特别用于实现事件和回调方法。所有的委托(Delegate)都派生自 System.Delegate 类。

       委托用于将方法作为参数传递给其他方法。 事件处理程序就是通过委托调用的方法。 你可以创建一个自定义方法,当发生特定事件时,某个类(如 Windows 控件)就可以调用你的方法。

        委托具有以下属性:

  • 委托类似于 C++ 函数指针,但它们是类型安全的。

  • 委托允许将方法作为参数进行传递。

  • 委托可用于定义回调方法。

  • 委托可以链接在一起;例如,可以对一个事件调用多个方法。

2、使用委托的步骤

     

第一步:定义委托

与类一样,委托类型必须在被用来创建变量以及类型对象之前声明。

委托的声明原型是 
delegate <函数返回类型> <委托名> (<函数参数>)

public delegate void MyDelegate ( );

第二步:委托的实例化,并将这个实例引用一个相匹配的方法

方法1:使用new关键字

<委托类型> <实例化名>=new <委托类型>(<注册函数>)

MyDelegate myIN = new MyDelegate(WriteToScreen);//实例化委托

pubic void WriteToScreen()
{
}

方法2:使用 += 号将实例引用一个相匹配的方法。

class Myclass
{
   public delegate void MyDelegate (); 
   MyDelegate  void myIN;//创建一个委托的实例

   public Myclass()
    {
      this.myIN +=run;
    }

    Private void run()
    {
     
    }
}

第三步:调用委托

完整步骤举例:

4、委托的作用

        委托时一种在C#中实现函数动态调用的方式,通过委托可以将一些相同类型的函数串联起来依次执行。委托同时还是函数回调事件机制的基础。

        实例化委托是将委托指向或引用某个方法,也就是必须要将某一个方法作为参数传递委托的构造方法

二、事件

1、 事件(Event) 基本上说是一个用户操作,如按键、点击、鼠标移动等等,或者是一些出现,如系统生成的通知。应用程序需要在事件发生时响应事件。例如,中断。事件是用于进程间通信。

        .NET中的事件,我们可以定义并捕捉特定的事件,并安排调用委托来处理发生的事件。

2、事件在类中声明且生成,且通过使用同一个类或其他类中的委托与事件处理程序关联。包含事件的类用于发布事件。这被称为 发布器(publisher) 类。其他接受该事件的类被称为 订阅器(subscriber) 类。事件使用 发布-订阅(publisher-subscriber) 模型。

发布器(publisher) 是一个包含事件和委托定义的对象。事件和委托之间的联系也定义在这个对象中。发布器(publisher)类的对象调用这个事件,并通知其他的对象。

订阅器(subscriber) 是一个接受事件并提供事件处理程序的对象。在发布器(publisher)类中的委托调用订阅器(subscriber)类中的方法(事件处理程序)。

3、声明事件

      由于事件的设计随同委托使用的,所以事件的类型必须是一个委托,而且在声明前附加event关键字作为前缀。

(1)在类的内部声明事件,首先必须声明该事件的委托类型。

如:

public delegate void BoilerLogHandler( );

(2)然后,声明事件本身,使用 event 关键字:

// 基于上面的委托定义事件
public event BoilerLogHandler BoilerEventLog;

定义了一个名为 BoilerLogHandler 的委托和一个名为 BoilerEventLog 的事件,该事件在生成的时候会调用委托

4、 发布-订阅(publisher-subscriber) 模型

(1)订阅事件:把方法添加到一个事件中。

发布器:看做是一个期刊社

订阅器:看做一个读者

     首先,读者订阅期刊社的一个期刊。相当于注册事件

     然后,当期刊要发行时,会通过电话、邮件等方式通知读者。相当于触发事件

     最后,当读者收到这个通知时候,会选择买期刊或者不买等一系列行为。相当于响应事件

举例: https://www.cnblogs.com/yinqixin/p/5056307.html

三、委托和事件应用举例

using System;
namespace SimpleEvent
{
  using System;
  /***********发布器类***********/
  public class EventTest
  {
    private int value;
    public delegate void NumManipulationHandler();//声明委托
    public event NumManipulationHandler ChangeNum;//声明事件

    protected virtual void OnNumChanged()
    {
      if ( ChangeNum != null )
      {
        ChangeNum(); /* 第三步事件被触发,执行事件处理方法*/
      }
     else 
      {
        Console.WriteLine( "event not fire" );
        Console.ReadKey(); /* 回车继续 */
      }
    }

    public EventTest()  //构造方法
    {
      int n = 5;
      SetValue( n );
    }


    public void SetValue( int n )
    {
      if ( value != n )
      {
        value = n;
        OnNumChanged();
      }
    }
  }


  /***********订阅器类***********/

  public class subscribEvent
  {
    public void printf()
    {
      Console.WriteLine( "event fire" );
      Console.ReadKey(); /* 回车继续 */
    }
  }

  /***********触发***********/
  public class MainClass
  {
    public static void Main()
    {
      EventTest e = new EventTest(); /* 实例化对象,第一次没有触发事件 */
      subscribEvent v = new subscribEvent(); /* 实例化对象 */
      e.ChangeNum += new EventTest.NumManipulationHandler( v.printf ); /* 第一步注册事件 */
      e.SetValue( 7 );//第二步触发事件,事件生成时调用委托
      e.SetValue( 11 );//第二步触发事件,事件生成时调用委托
    }
  }
}

当上面的代码被编译和执行时,它会产生下列结果:

event not fire

event fire

event fire

另外一个例子:C#事件的订阅与触发

四、WPF实现关闭子窗口B时触发A窗口事件

       最后总结简单的委托事件的应用只需要五步法。

1、定义子窗口B

发布器功能:

  //第一步,定义委托,委拖不属于任何一个类
  public delegate void ChangeTextHandler();
  public partial class B : Window   //事件发布类
{
    //第二步,声明事件
    public event ChangeTextHandler ChangeTextEvent;
    public B()
     {
        InitializeComponent();
     }

     //点击子窗口B上的一个按钮触发事件
     private void btnCalibraEnter_Click(object sender, RoutedEventArgs e)
      {
          this.Close();//关闭窗口B
          //第四步,调用事件
          ChangeTextEvent();
      }
}

2、定义窗口A,通过窗口A打开子窗口B,打开子窗口B后立即关闭窗口A

订阅器功能:

public partial class A : Window
{
    public A()
    {
            InitializeComponent();
    }

     
    //点击窗口A上的按钮,关闭窗口A,并注册事件
     private void btnNext_Click(object sender, RoutedEventArgs e)
        {
            this.Close();//关闭当前窗口
            //例化窗口B
            B demaWin = new B();
            demaWin.ChangeTextEvent += new ChangeTextHandler(method);//第三步,注册事件
            demaWin.Show();//打开窗口B

        }

        //第五步,事件发生时要调用的方法
        private void method() 
        {
           //虽然当前窗口A已经关闭,但是事件触发时,程序依然可以执行到这里
        }
   
}

猜你喜欢

转载自blog.csdn.net/kenjianqi1647/article/details/84134731