猿教程 Logo

C# 事件

阿里云服务器,每月低至7.8元,项目演示即建站必备,比腾讯云更便宜,并且不需学生认证,从此链接购买有效:去购买

一般来说,事件是一件特别的事情。例如,Microsoft为开发人员启动事件,以使他们了解新产品或现有产品的功能。 Microsoft通过电子邮件或其他广告选项通知开发人员该事件。因此,在这种情况下,Microsoft是发布(提出)事件并通知开发者关于它的发布者,开发者是事件的订阅者并参与(处理)事件。

C#中的事件遵循类似的概念。事件具有发布者,订阅者,通知和处理程序。通常,UI控件广泛地使用事件。例如,Windows窗体中的按钮控件具有多个事件,例如点击,鼠标悬停等。自定义类也可以具有事件以通知其他订阅者类已经发生或将要发生的事情。让我们看看如何定义一个事件并通知其他具有事件处理程序的类。

事件只是一个封装的委托。正如我们在上一节中学到的,一个委托是一个引用类型的数据类型。您可以声明委托,如下所示:

相关实例:

public delegate void someEvent();

public someEvent someEvent;

现在,要声明一个事件,在声明一个委托类型的变量之前,使用event关键字,如下所示:

相关实例:

public delegate void someEvent();

public event someEvent someEvent;

因此,委托变成了使用event关键字的事件。

现在,让我们看一个事件的一个实际例子。 考虑下面的PrintHelper类,它以不同的格式(如数字,金钱,十进制,温度和十六进制)打印整数。 它包括一个beforePrintEvent,用于在打印号码之前通知订阅者BeforePrint事件。

相关实例:

public class PrintHelper
{
    // declare delegate 
    public delegate void BeforePrint();
    
    //declare event of type delegate
    public event BeforePrint beforePrintEvent;
      
    public PrintHelper()
    {

    }

    public void PrintNumber(int num)
    {
    //call delegate method before going to print
        if (beforePrintEvent != null)
            beforePrintEvent();

        Console.WriteLine("Number: {0,-12:N0}", num);
    }

    public void PrintDecimal(int dec)
    {
        if (beforePrintEvent != null)
            beforePrintEvent();
    
        Console.WriteLine("Decimal: {0:G}", dec);
    }

    public void PrintMoney(int money)
    {
        if (beforePrintEvent != null)
            beforePrintEvent();

        Console.WriteLine("Money: {0:C}", money);
    }

    public void PrintTemperature(int num)
    {
        if (beforePrintEvent != null)
            beforePrintEvent();

        Console.WriteLine("Temperature: {0,4:N1} F", num);
    }
    public void PrintHexadecimal(int dec)
    {
        if (beforePrintEvent != null)
            beforePrintEvent();

        Console.WriteLine("Hexadecimal: {0:X}", dec);
    }
}

PrintHelper是发布beforePrint事件的发布者类。 注意,在每个打印方法中,它首先检查beforePrintEvent是否不为null,然后调用beforePrintEvent()。 beforePrintEvent是BeforPrint委托类型的对象,因此如果没有类被订阅事件,那么它将是null,这就是为什么在调用委托之前需要检查null。

现在,让我们创建一个订阅者。 例如,考虑下面的简单Number类。

相关实例:

class Number
{
    private PrintHelper _printHelper;

    public Number(int val)
    {
        _value = val;
           
        _printHelper = new PrintHelper();
        //subscribe to beforePrintEvent event
        _printHelper.beforePrintEvent += printHelper_beforePrintEvent;
    }
    //beforePrintevent handler
    void printHelper_beforePrintEvent()
    {
        Console.WriteLine("BeforPrintEventHandler: PrintHelper is going to print a value");
    }

    private int _value;

    public int Value
    {
        get { return _value; }
        set { _value = value; }
    }

    public void PrintMoney()
    {
        _printHelper.PrintMoney(_value);
    }

    public void PrintNumber()
    {
        _printHelper.PrintNumber(_value);
    }
}

所有订阅者都必须提供一个处理函数,当发布者引发事件时,该函数将被调用。 在上面的例子中,Number类创建了一个PrintHelper实例,并使用“+ =”运算符预订了beforePrintEvent,并给出了处理事件的函数的名称(当发布触发事件时,它将被调用)。 printHelper_beforePrintEvent是与PrintHelper类中的BeforePrint委托具有相同签名的事件处理程序。

现在,创建一个Number类的实例并调用print方法:

相关实例:

Number myNumber = new Number(100000);
myNumber.PrintMoney();
myNumber.PrintNumber();

运行结果:

BeforePrintEventHandler: PrintHelper is going to print value 
Money: $ 1,00,000.00
BeforePrintEventHandler: PrintHelper is going to print value 
Number: 1,00,000

下图说明了事件模型:



事件参数

事件还可以将数据作为参数传递到它们的订阅处理程序。 事件根据委托签名将参数传递给处理程序。 在下面的示例中,PrintHelper声明了接受字符串参数的BeforePrint委托。 现在,当您从PrintNumber或任何其他Print方法引发事件时,您可以传递一个字符串。

相关实例:

public class PrintHelper
{
    public delegate void BeforePrint(string message);
    public event BeforePrint beforePrintEvent;

    public PrintHelper()
    {

    }

    public void PrintNumber(int num)
    {
        if (beforePrintEvent != null)
            beforePrintEvent.Invoke("PrintNumber");

        Console.WriteLine("Number: {0,-12:N0}", num);

    }

    public void PrintDecimal(int dec)
    {
        if (beforePrintEvent != null)
            beforePrintEvent("PrintDecimal");

        Console.WriteLine("Decimal: {0:G}", dec);
    }

    public void PrintMoney(int money)
    {
        if (beforePrintEvent != null)
            beforePrintEvent("PrintMoney");

        Console.WriteLine("Money: {0:C}", money);
    }

    public void PrintTemperature(int num)
    {
        if (beforePrintEvent != null)
            beforePrintEvent("PrintTemerature");

        Console.WriteLine("Temperature: {0,4:N1} F", num);
    }
    public void PrintHexadecimal(int dec)
    {
        if (beforePrintEvent != null)
            beforePrintEvent("PrintHexadecimal");

        Console.WriteLine("Hexadecimal: {0:X}", dec);
    }
}

现在,订阅者类应该有一个具有字符串参数的事件处理程序。

在下面的示例中,Number类具有带有string参数的printHelper_beforePrintEvent函数。

相关实例:

class Number
{
    private PrintHelper _printHelper;

    public Number(int val)
    {
        _value = val;
           
        _printHelper = new PrintHelper();
        //subscribe to beforePrintEvent event
        _printHelper.beforePrintEvent += printHelper_beforePrintEvent;
    }
    //beforePrintevent handler
    void printHelper_beforePrintEvent(string message)
    {
        Console.WriteLine("BeforePrintEvent fires from {0}",message);
    }

    private int _value;

    public int Value
    {
        get { return _value; }
        set { _value = value; }
    }

    public void PrintMoney()
    {
        _printHelper.PrintMoney(_value);
    }

    public void PrintNumber()
    {
        _printHelper.PrintNumber(_value);
    }

}

运行结果:

BeforePrintEvent fires from PrintMoney.
Money: $ 1,00,000.00
BeforePrintEvent fires from PrintNumber.
Number: 1,00,000

更多参考资料

委托和事件

重点
  1. 对委托类型使用event关键字来声明事件。

  2. 触发一个事件之前需要检查事件是否为null。

  3. 使用“+ =”运算符预订事件。 使用“ - =”运算符取消订阅。

  4. 处理事件的函数称为事件处理程序。 事件处理程序必须具有与事件委托所声明的相同的签名。

  5. 事件可以具有将被传递给处理函数的参数。

  6. 事件也可以声明为静态,虚拟,密封和抽象。

  7. 接口可以将事件包括为成员。

  8. 如果没有订阅者,则不会引发事件

  9. 如果有多个订阅者,则同步调用事件处理程序

  10. .NET框架使用EventHandler委托和EventArgs基类。

阿里云服务器,每月低至7.8元,项目演示即建站必备,比腾讯云更便宜,并且不需学生认证,从此链接购买有效: 去购买


版权声明:本站所有教程均为本站原创或翻译,转载请注明出处,请尊重他人劳动果实。请记住本站地址:www.yuanjiaocheng.net (猿教程) 作者:卿文刚
本文标题: C#环境
本文地址:http://www.yuanjiaocheng.net/CSharp/csharp-event.html