iis服务器助手广告
返回顶部
首页 > 资讯 > 精选 >如何理解.Net事件
  • 789
分享到

如何理解.Net事件

2023-06-17 08:06:57 789人浏览 薄情痞子
摘要

今天就跟大家聊聊有关如何理解.net事件,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。.NET 事件事件概述在发生其他类或对象关注的事情时,类或对象可通过事件通知它们。发送(或引发)

今天就跟大家聊聊有关如何理解.net事件,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

.NET 事件

事件概述

在发生其他类或对象关注的事情时,类或对象可通过事件通知它们。发送(或引发)事件的类称为“发行者”,接收(或处理)事件的类称为“订户”。

  • 特点

    • 发行者确定何时引发事件,订户确定执行何种操作来响应该事件。

    • 一个事件可以有多个订户。一个订户可处理来自多个发行者的多个事件。

    • 没有订户的事件永远不会被调用。

    • 事件通常用于通知用户操作

    • 如果一个事件有多个订户,当引发该事件时,会同步调用多个事件处理程序,也可以设置异步调用事件。

    • 可以利用事件同步线程

    • 事件是基于 EventHandler 委托和 EventArgs 基类的。

事件的订阅和取消

如果您想编写引发事件时调用的自定义代码,则可以订阅由其他类发布的事件。例如,可以订阅某个按钮的“单击”事件,以使应用程序在用户单击该按钮时执行一些有用的操作。

  • 订阅事件

    • 如果“属性”窗口不可见,请在“设计”视图中,右击要创建事件处理程序的窗体或控件,然后选择“属性”。

    • 在“属性”窗口的顶部,单击“事件”图标。

    • 双击要创建的事件,Visual C#  会创建一个空事件处理程序方法,并将其添加到您的代码中。或者,您也可以在“代码”视图中手动添加代码。

    • VS IDE 订阅事件

  • 编程方式订阅事件

    • 定义一个事件处理程序方法,其签名与该事件的委托签名匹配。例如,如果事件基于  EventHandler 委托类型,则下面的代码表示方法存根


    • 使用加法赋值运算符 (+=) 来为事件附加事件处理程序。在下面的示例中,假设名为 publisher  的对象拥有一个名为 RaiseCustomEvent 的事件。请注意,订户类需要引用发行者类才能订阅其事件。

    1. oid HandleCustomEvent(object sender, CustomEventArgs a){  } 

publisher.RaiseCustomEvent += HandleCustomEvent; publisher.RaiseCustomEvent += new CustomEventHandler(HandleCustomEvent);
  • 匿名方法订阅事件

    • 使用加法赋值运算符 (+=) 来为事件附加匿名方法。在下面的示例中,假设名为  publisher 的对象拥有一个名为 RaiseCustomEvent 的事件,并且还定义了一个 CustomEventArgs  类以承载某些类型的专用事件信息。请注意,订户类需要引用 publisher 才能订阅其事件。

  1. publisher.RaiseCustomEvent += delegate(object o, CustomEventArgs e) 

  2.     string s = o.ToString() + " " + e.ToString(); 

  3.     Console.WriteLine(s); 

  4. };

  • 取消订阅

要防止在引发事件时调用事件处理程序,您只需取消订阅该事件。要防止资源泄露,请在释放订户对象之前取消订阅事件,这一点很重要。在取消订阅事件之前,在发布对象中作为该事件的基础的多路广播委托会引用封装了订户的事件处理程序的委托。只要发布对象包含该引用,就不会对订户对象执行垃圾回收。

使用减法赋值运算符 (-=)  取消订阅事件。所有订户都取消订阅某事件后,发行者类中的事件实例会设置为 null。

publisher.RaiseCustomEvent -= HandleCustomEvent;

发布标准事件

下面的过程演示了如何将符合标准 .NET Framework 模式的事件添加到您自己的类和结构中。.NET Framework 类库中的所有事件均基于  EventHandler 委托,定义如下。

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

  • 采用 EventHandler  模式发布事件

    • 如果没有自定义 EventArgs 类,事件类型就是非泛型 EventHandler  委托。它无需声明,因为它已在 C# 项目默认包含的 System 命名空间中进行了声明

    •  


    • 如果使用的是 EventHandler 的非泛型版本,并且您有一个由 EventArgs  派生的自定义类,请在发布类中声明您的事件,并且将您的委托用作类型

    •  


    • 如果使用的是泛型版本,则不需要自定义委托。相反,应将事件类型指定为  EventHandler<CustomEventArgs>,在尖括号内放置您自己的类的名称。


    • (如果不需要发送含事件的自定义数据,请跳过此步骤,直接进入步骤  3。)在发行者类和订户类均可看见的范围中声明类,并添加保留自定义事件数据所需的成员。在此示例中,会返回一个简单字符串

    •  


    • (如果您使用的是 EventHandler  的泛型版本,请跳过此步骤。)在发布类中声明一个委托。为它指定以 EventHandler 结尾的名称。第二个参数指定自定义 EventArgs  类型。

    •  


    • 使用以下任一步骤,在发布类中声明事件。

    1. public event EventHandler RaiseCustomEvent; 

    1. class Publisher 

    2.     public event CustomEventHandler RaiseCustomEvent; 

    1. public event EventHandler<CustomEventArgs> RaiseCustomEvent; 

    1. public delegate void CustomEventHandler(object sender, CustomEventArgs a); 

    1. public class CustomEventArgs : EventArgs 

    2.     public CustomEventArgs(string s) 

    3.     { 

    4.         msg = s; 

    5.     } 

    6.     private string msg; 

    7.     public string Message 

    8.     { 

    9.         get { return msg; } 

    10.     }  

引发派生类中的基类事件

 以下简单示例演示了在基类中声明可从派生类引发的事件的标准方法。此模式广泛应用于 .NET Framework 基类库中的 windows  窗体类。

在创建可用作其他类的基类的类时,必须考虑如下事实:事件是特殊类型的委托,只可以从声明它们的类中调用。派生类无法直接调用基类中声明的事件。尽管有时您可能希望某个事件只能通过基类引发,但在大多数情形下,您应该允许派生类调用基类事件。为此,您可以在包含该事件的基类中创建一个受保护的调用方法。通过调用或重写此调用方法,派生类便可以间接调用该事件。

namespace BaseClassEvents {     using System;     using System.Collections.Generic;     public class ShapeEventArgs : EventArgs     {         private double newArea;          public ShapeEventArgs(double d)         {             newArea = d;         }         public double NewArea         {             get { return newArea; }         }     }     public abstract class Shape     {         protected double area;          public double Area         {             get { return area; }             set { area = value; }         }         public event EventHandler<ShapeEventArgs> ShapeChanged;         public abstract void Draw();         protected virtual void OnShapeChanged(ShapeEventArgs e)         {             EventHandler<ShapeEventArgs> handler = ShapeChanged;             if (handler != null)             {                 handler(this, e);             }         }     }     public class Circle : Shape     {         private double radius;         public Circle(double d)         {             radius = d;             area = 3.14 * radius;         }         public void Update(double d)         {             radius = d;             area = 3.14 * radius;             OnShapeChanged(new ShapeEventArgs(area));         }         protected override void OnShapeChanged(ShapeEventArgs e)         {             base.OnShapeChanged(e);         }         public override void Draw()         {             Console.WriteLine("Drawing a circle");         }     }     public class Rectangle : Shape     {         private double length;         private double width;         public Rectangle(double length, double width)         {             this.length = length;             this.width = width;             area = length * width;         }         public void Update(double length, double width)         {             this.length = length;             this.width = width;             area = length * width;             OnShapeChanged(new ShapeEventArgs(area));         }         protected override void OnShapeChanged(ShapeEventArgs e)         {             base.OnShapeChanged(e);         }         public override void Draw()         {             Console.WriteLine("Drawing a rectangle");         }      }     public class ShapeContainer     {         List<Shape> _list;          public ShapeContainer()         {             _list = new List<Shape>();         }          public void AddShape(Shape s)         {             _list.Add(s);             s.ShapeChanged += HandleShapeChanged;         }         private void HandleShapeChanged(object sender, ShapeEventArgs e)         {             Shape s = (Shape)sender;             Console.WriteLine("Received event. Shape area is now {0}", e.NewArea);             s.Draw();         }     }     class Test     {          static void Main(string[] args)         {             Circle c1 = new Circle(54);             Rectangle r1 = new Rectangle(12, 9);             ShapeContainer sc = new ShapeContainer();             sc.AddShape(c1);             sc.AddShape(r1);             c1.Update(57);             r1.Update(7, 7);             Console.WriteLine();             Console.WriteLine("Press Enter to exit");             Console.ReadLine();         }     } }

实现接口事件

接口可声明事件。下面的示例演示如何在类中实现接口事件。接口事件的实现规则与任何接口方法或属性的实现规则基本相同。

  • 在类中实现接口事件

     在类中声明事件,然后在适当的位置调用该事件。

  1. public interface IDrawinGobject 

  2.     event EventHandler ShapeChanged; 

  3. public class MyEventArgs : EventArgs {&hellip;} 

  4. public class Shape : IDrawingObject 

  5.     event EventHandler ShapeChanged; 

  6.     void ChangeShape() 

  7.     { 

  8.         // Do something before the event&hellip; 

  9.         OnShapeChanged(new MyEventsArgs(&hellip;)); 

  10.         // or do something after the event.  

  11.     } 

  12.     protected virtual void OnShapeChanged(MyEventArgs e) 

  13.     { 

  14.         if(ShapeChanged != null) 

  15.         { 

  16.            ShapeChanged(this, e); 

  17.         } 

  18.     } 

  19. }

下面的示例演示如何处理以下的不常见情况:您的类是从两个以上的接口继承的,每个接口都含有同名事件)。在这种情况下,您至少要为其中一个事件提供显式接口实现。为事件编写显式接口实现时,必须编写  add 和 remove 事件访问器。这两个事件访问器通常由编译器提供,但在这种情况下编译器不能提供。

您可以提供自己的访问器,以便指定这两个事件是由您的类中的同一事件表示,还是由不同事件表示。例如,根据接口规范,如果事件应在不同时间引发,则可以将每个事件与类中的一个单独实现关联。在下面的示例中,订户将形状引用强制转换为  IShape 或 IDrawingObject,从而确定自己将会接收哪个 OnDraw 事件。

namespace WrapTwoInterfaceEvents {     using System;     public interface IDrawingObject     {         event EventHandler OnDraw;     }     public interface IShape     {         event EventHandler OnDraw;     }     public class Shape : IDrawingObject, IShape     {         event EventHandler PreDrawEvent;         event EventHandler PostDrawEvent;         event EventHandler IDrawingObject.OnDraw         {             add { PreDrawEvent += value; }             remove { PreDrawEvent -= value; }         }         event EventHandler IShape.OnDraw         {             add { PostDrawEvent += value; }             remove { PostDrawEvent -= value; }         }         public void Draw()         {             EventHandler handler = PreDrawEvent;             if (handler != null)             {                 handler(this, new EventArgs());             }             Console.WriteLine("Drawing a shape.");             handler = PostDrawEvent;             if (handler != null)             {                 handler(this, new EventArgs());             }         }     }     public class Subscriber1     {         public Subscriber1(Shape shape)         {             IDrawingObject d = (IDrawingObject)shape;             d.OnDraw += new EventHandler(d_OnDraw);         }         void d_OnDraw(object sender, EventArgs e)         {             Console.WriteLine("Sub1 receives the IDrawingObject event.");         }     }     public class Subscriber2     {         public Subscriber2(Shape shape)         {             IShape d = (IShape)shape;             d.OnDraw += new EventHandler(d_OnDraw);         }          void d_OnDraw(object sender, EventArgs e)         {             Console.WriteLine("Sub2 receives the IShape event.");         }     }     public class Program     {         static void Main(string[] args)         {             Shape shape = new Shape();             Subscriber1 sub = new Subscriber1(shape);             Subscriber2 sub2 = new Subscriber2(shape);             shape.Draw();              Console.WriteLine("Press Enter to close this window.");             Console.ReadLine();         }     } }

使用字典存储事件实例

accessor-declarations  的一种用法是公开大量的事件但不为每个事件分配字段,而是使用字典来存储这些事件实例。这只有在具有非常多的事件、但您预计大部分事件都不会实现时才有用。

  1. public delegate void EventHandler1(int i); 

  2. public delegate void EventHandler2(string s); 

  3. public class PropertyEventsSample 

  4.     private System.Collections.Generic.Dictionary<string, System.Delegate> eventTable; 

  5.     public PropertyEventsSample() 

  6.     { 

  7.         eventTable = new System.Collections.Generic.Dictionary<string, System.Delegate>(); 

  8.         eventTable.Add("Event1", null); 

  9.         eventTable.Add("Event2", null); 

  10.     } 

  11.     public event EventHandler1 Event1 

  12.     { 

  13.         add 

  14.         { 

  15.             eventTable["Event1"] = (EventHandler1)eventTable["Event1"] + value; 

  16.         } 

  17.         remove 

  18.         { 

  19.             eventTable["Event1"] = (EventHandler1)eventTable["Event1"] - value; 

  20.         } 

  21.     } 

  22.     public event EventHandler2 Event2 

  23.     { 

  24.         add 

  25.         { 

  26.             eventTable["Event2"] = (EventHandler2)eventTable["Event2"] + value; 

  27.         } 

  28.         remove 

  29.         { 

  30.             eventTable["Event2"] = (EventHandler2)eventTable["Event2"] - value; 

  31.         } 

  32.     } 

  33.     internal void RaiseEvent1(int i) 

  34.     { 

  35.         EventHandler1 handler1; 

  36.         if (null != (handler1 = (EventHandler1)eventTable["Event1"])) 

  37.         { 

  38.             handler1(i); 

  39.         } 

  40.     } 

  41.     internal void RaiseEvent2(string s) 

  42.     { 

  43.         EventHandler2 handler2; 

  44.         if (null != (handler2 = (EventHandler2)eventTable["Event2"])) 

  45.         { 

  46.             handler2(s); 

  47.         } 

  48.     } 

  49. public class TestClass 

  50.     public static void Delegate1Method(int i) 

  51.     { 

  52.         System.Console.WriteLine(i); 

  53.     } 

  54.     public static void Delegate2Method(string s) 

  55.     { 

  56.         System.Console.WriteLine(s); 

  57.     } 

  58.     static void Main() 

  59.     { 

  60.         PropertyEventsSample p = new PropertyEventsSample(); 

  61.  

  62.         p.Event1 += new EventHandler1(TestClass.Delegate1Method); 

  63.         p.Event1 += new EventHandler1(TestClass.Delegate1Method); 

  64.         p.Event1 -= new EventHandler1(TestClass.Delegate1Method); 

  65.         p.RaiseEvent1(2); 

  66.  

  67.         p.Event2 += new EventHandler2(TestClass.Delegate2Method); 

  68.         p.Event2 += new EventHandler2(TestClass.Delegate2Method); 

  69.         p.Event2 -= new EventHandler2(TestClass.Delegate2Method); 

  70.         p.RaiseEvent2("TestString"); 

  71.     } 

  72. }

事件的异步模式

有多种方式可向客户端代码公开异步功能。基于事件的异步模式为类规定了用于显示异步行为的建议方式。对于相对简单的多线程应用程序,BackgroundWorker  组件提供了一个简单的解决方案。对于更复杂的异步应用程序,请考虑实现一个符合基于事件的异步模式的类。

  • “在后台”执行耗时任务(例如下载和数据库操作),但不会中断您的应用程序。

  • 同时执行多个操作,每个操作完成时都会接到通知。

  • 等待资源变得可用,但不会停止(“挂起”)您的应用程序。

  • 使用熟悉的事件和委托模型与挂起的异步操作通信。

看完上述内容,你们对如何理解.Net事件有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注编程网精选频道,感谢大家的支持。

--结束END--

本文标题: 如何理解.Net事件

本文链接: https://www.lsjlt.com/news/287925.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • 如何理解.Net事件
    今天就跟大家聊聊有关如何理解.Net事件,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。.NET 事件事件概述在发生其他类或对象关注的事情时,类或对象可通过事件通知它们。发送(或引发)...
    99+
    2023-06-17
  • 如何理解.NET静态事件链
    本篇文章为大家展示了如何理解.NET静态事件链,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。在我们日常开发过程中经常会遇到多个类实例之间的关联,不管是B/S还是C/S的项目,在对实例的使用是一样的;...
    99+
    2023-06-17
  • 如何理解.Net异常处理
    本篇文章给大家分享的是有关如何进行.Net异常处理,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。异常处理     可以使用 TryCatch 活动...
    99+
    2023-06-17
  • 如何理解Python 键盘事件
    本篇文章给大家分享的是有关如何理解Python 键盘事件,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。键盘事件废话不多说直接上包from selenium.webdr...
    99+
    2023-06-25
  • 如何理解javascript事件委托
    这篇文章主要介绍“如何理解javascript事件委托”,在日常操作中,相信很多人在如何理解javascript事件委托问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”如何理解...
    99+
    2024-04-02
  • 如何理解.NET的反射
    这期内容当中小编将会给大家带来有关如何解.NET的反射,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。反射反射提供了封装程序集、模块和类型的对象(Type  类型)。可以使用反射动态创建类型的实例...
    99+
    2023-06-17
  • 如何理解Vue中的事件处理和事件修饰符
    这篇文章将为大家详细讲解有关如何理解Vue中的事件处理和事件修饰符,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。 <div id="root"&...
    99+
    2023-06-25
  • 如何理解.NET Core Dto映射
    如何理解.NET Core Dto映射,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。我们假设一个场景, 采用EF Core+Web Api, 这时候可能会出现E...
    99+
    2023-06-05
  • cad缺少net组件如何解决
    这篇“cad缺少net组件如何解决”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“cad缺少net组件如何解决”文章吧。cad...
    99+
    2023-07-02
  • 如何理解Nodejs中的事件循环
    这期内容当中小编将会给大家带来有关如何理解Nodejs中的事件循环,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Node事件循环Node底层使用的语言libuv,是一个c...
    99+
    2024-04-02
  • 如何理解.NET Native及其应用
    本篇文章为大家展示了如何理解.NET Native及其应用,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。.NET Native.NET Native 可以将 C# 代码编译为本地机器码。据博客介绍,...
    99+
    2023-06-17
  • 如何理解.NET 4并行编程
    这期内容当中小编将会给大家带来有关如何理解.NET 4并行编程,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。1.并行编程和多线程编程的区别。1并行编程。现在随着多核计算机的普及,并行编程技术,也就是多核编...
    99+
    2023-06-17
  • 如何理解.NET代码转换器
    这篇文章将为大家详细讲解有关如何理解.NET代码转换器,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。想把.NET的代码(C#和VB.NET)互转吗?或是转成Python或Ruby吗?在网站上...
    99+
    2023-06-17
  • 如何理解.NET MVVM设计模式
    如何理解.NET MVVM设计模式,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。MVVM 模式能够帮你把你程序的业务与展现逻辑从用户界面干净地分离开。保持程序逻辑与界面分离能够...
    99+
    2023-06-17
  • NET类库封装该如何理解
    这篇文章跟大家分析一下“NET类库封装该如何理解”。内容详细易懂,对“NET类库封装该如何理解”感兴趣的朋友可以跟着小编的思路慢慢深入来阅读一下,希望阅读后能够对大家有所帮助。下面跟着小编一起深入学习“NET类库封装该如何理解”的知识吧。目...
    99+
    2023-06-17
  • 如何理解针对不同.NET版本的条件编译
    本篇文章给大家分享的是有关如何理解针对不同.NET版本的条件编译,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。为了在 .NET 2.0 下能够编译成功,我写了一个文件 Patc...
    99+
    2023-06-17
  • 如何理解Vue中组件的自定义事件
    本篇文章为大家展示了如何理解Vue中组件的自定义事件,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。<template>  <div > ...
    99+
    2023-06-25
  • Swoole中如何理解进程和事件IO
    本篇文章为大家展示了Swoole中如何理解进程和事件IO,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。1.文件锁子进程回复制父进程的IO句柄,但是不能让所有的子进程...
    99+
    2024-04-02
  • vue.js的事件循环机制如何理解
    这篇文章主要介绍了vue.js的事件循环机制如何理解的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇vue.js的事件循环机制如何理解文章都会有所收获,下面我们一起来看看吧。一、事件循环机制介绍  &n...
    99+
    2023-06-29
  • 如何理解.NET和Java发展前景
    这篇文章主要讲解了“如何理解.NET和Java发展前景”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“如何理解.NET和Java发展前景”吧!.NET和Java发展前景哪个好在编程语言中Jav...
    99+
    2023-06-15
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作