C#事件(event)解析

【AMD显卡在WIndow10/11部署带GPU支持的深度学习环境(Pytorch-DirectML篇)】 这篇是之前Tensorflow-DirectML的姊妹篇,如果对TF感兴趣的可以搜索我的博文。 首先我们丢一个官网地址,但是官网那个会误导新人如果你按那个操作的话。 https://docs.microsoft.com/en-us/windows/ai/directml/gpu-pytorch-windows 这里用我的方法操作: 首先声明一下,因为我的显卡是AMD RX6600,不带XT(性能和RTX3060 12G版本半斤八两),所以目前没有最新的WSL2驱动,如果有了的话欢迎告知我,所以我这里就. 阅读详情
 事件(event),这个词儿对于初学者来说,往往总是显得有些神秘,不易弄懂。而这些东西却往往又是编程中常用且非常重要的东西。大家都知道windows消息处理机制的重要,其实C#事件就是基于windows消息处理机制的,只是封装的更好,让开发者无须知道底层的消息处理机制,就可以开发出强大的基于事件的应用程序来。

先来看看事件编程有哪些好处。
在以往我们编写这类程序中,往往采用等待机制,为了等待某件事情的发生,需要不断地检测某些判断变量,而引入事件编程后,大大简化了这种过程:
- 使用事件,可以很方便地确定程序执行顺序。
- 当事件驱动程序等待事件时,它不占用很多资源。事件驱动程序与过程式程序最大的不同就在于,程序不再不停地检查输入设备,而是呆着不动,等待消息的到来,每个输入的消息会被排进队列,等待程序处理它。如果没有消息在等待,则程序会把控制交回给操作系统,以运行其他程序。
- 事件简化了编程。操作系统只是简单地将消息传送给对象,由对象的事件驱动程序确定事件的处理方法。操作系统不必知道程序的内部工作机制,只是需要知道如何与对象进行对话,也就是如何传递消息。

  有了这么多好处,看来我们的确有必要掌握它。俗话说:“难了不会,会了不难”。就让我们一步一步开始吧...

  要讲事件,必然要讲到委托(delegate)。它们之间的关系可以通过一个浅显的比方来说明,这个比方可能不是十分恰当。比如你要租一个房屋,这是一个事件,那么委托就是房屋租赁中介,当你把租房子的消息告知中介后,中介就会产生出一套符合你要求的房屋租赁方案来。再由中介执行这套方案,你便租得了这个房屋,即事件被处理了。当然你也可以不通过中介,直接找房东,但如果没有互联网等工具,你如何得到谁出租房屋的信息?话题扯远了。

委托(delegate)
委托可以理解成为函数指针,不同的是委托是面向对象,而且是类型安全的。关于委托的理解,可以参考我的另一篇文章《C#委托之个人理解》。

事件(event)
  我们可以把事件编程简单地分成两个部分:事件发生的类(书面上叫事件发生器)和事件接收处理的类。事件发生的类就是说在这个类中触发了一个事件,但这个类并不知道哪个个对象或方法将会加收到并处理它触发的事件。所需要的是在发送方和接收方之间存在一个媒介。这个媒介在.NET Framework中就是委托(delegate)。在事件接收处理的类中,我们需要有一个处理事件的方法。好了,我们就按照这个顺序来实现一个捕获键盘按键的程序,来一步一步说明如何编写事件应用程序。

1、首先创建一个自己的EventArgs类。
引自MSDN:
EventArgs是包含事件数据的类的基类,此类不包含事件数据,在事件引发时不向事件处理程序传递状态信息的事件会使用此类。如果事件处理程序需要状态信息,则应用程序必须从此类派生一个类来保存数据。

因为在我们键盘按键事件中要包含按键信息,所以要派生一个KeyEventArgs类,来保存按键信息,好让后面知道按了哪个键。

internal   class  KeyEventArgs : EventArgs
{
    
private char keyChar;
    
public KeyEventArgs( char keyChar ) : base()
    
{
        
this.keyChar = keyChar;
    }


    
public char KeyChar
    
{
        
get
        
{
            
return keyChar;
        }

    }

}


2、再创建一个事件发生的类KeyInputMonitor,这个类用于监控键盘按键的输入并触发一个事件:

internal   class  KeyInputMonitor
{
    
// 创建一个委托,返回类型为void,两个参数
    public delegate void KeyDownHandler( object sender, KeyEventArgs e );
    
// 将创建的委托和特定事件关联,在这里特定的事件为KeyDown
    public event KeyDownHandler KeyDown;

    
public void Run()
    
{
        
bool finished = false;
        
do
        
{
            Console.WriteLine( 
"Input a char" );
            
string response = Console.ReadLine();

            
char responseChar = ( response == "" ) ? ' ' : char.ToUpper( response[0] );
            
switch( responseChar )
            
{
                
case 'X':
                    finished 
= true;
                    
break;
                
default:
                    
// 得到按键信息的参数
                    KeyEventArgs keyEventArgs = new KeyEventArgs( responseChar );
                    
// 触发事件
                    KeyDown( this, keyEventArgs );
                    
break;
            }

        }
while( !finished );
    }

}


这里注意KeyDown( this, KeyEventArgs );一句,这就是触发事件的语句,并将事件交由KeyDownHandler这个委托来处理,委托指定事件处理方法去处理事件,这就是事件接收方的类的事情了。参数this是指触发事件的对象就是本身这个对象,keyEventArgs包含了按键信息。

3、最后创建一个事件接收方的类,这个类先产生一个委托实例,再把这个委托实例添加到产生事件对象的事件列表中去,这个过程又叫订阅事件。然后提供一个方法回显按键信息。

internal   class  EventReceiver
{
    
public EventReceiver( KeyInputMonitor monitor )
    
{
        
// 产生一个委托实例并添加到KeyInputMonitor产生的事件列表中
        monitor.KeyDown += new KeyInputMonitor.KeyDownHandler( this.OnKeyDown );
    }

    
private void OnKeyDown(object sender, KeyEventArgs e)
    
{
        
// 真正的事件处理函数
        Console.WriteLine( "Capture key: {0}", e.KeyChar );
    }

}


4、看一下如何调用

public   class  MainEntryPoint
{
    
public static void Start()
    
{
        
// 实例化一个事件发送器
        KeyInputMonitor monitor = new KeyInputMonitor();
        
// 实例化一个事件接收器
        EventReceiver eventReceiver = new EventReceiver( monitor );
        
// 运行
        monitor.Run();
    }

}


总结:

C#中使用事件需要的步骤:
1.创建一个委托
2.将创建的委托与特定事件关联(.Net类库中的很多事件都是已经定制好的,所以他们也就有相应的一个委托,在编写关联事件处理程序--也就是当有事件发生时我们要执行的方法的时候我们需要和这个委托有相同的签名)
3.编写事件处理程序
4.利用编写的事件处理程序生成一个委托实例
5.把这个委托实例添加到产生事件对象的事件列表中去,这个过程又叫订阅事件

C#中事件产生和实现的流程:
1.定义A为产生事件的实例,a为A产生的一个事件
2.定义B为接收事件的实例,b为处理事件的方法
3.A由于用户(程序编写者或程序使用者)或者系统产生一个a事件(例如点击一个Button,产生一个Click事件)
4.A通过事件列表中的委托对象将这个事件通知给B
5.B接到一个事件通知(实际是B.b利用委托来实现事件的接收)
6.调用B.b方法完成事件处理
    public class A
    {
        public delegate void EventHandler(object sender);
        public event EventHandler a;

        public void Run()
        {
            Console.WriteLine("Trigger an event.");
            a(this);
        }
    }

    class B
    {
        public B(A a)
        {
            a.a += new A.EventHandler(this.b);
        }
        private void b(object sender)
        {
            Console.WriteLine("Received and handled an event." );
            Console.Read();
        }
    }

这有一个很好的例子,有助于理解事件机制。 

using System; 

namespace Vczx.ProCSharp.Event 
{ 
/// <summary> 
/// 类EatEventArgs 必须继承自类EventArgs,用来引发事件时封装数据 
/// </summary> 
public class EatEventArgs : EventArgs 
{ 
public String restrauntName; //饭店名称 
public decimal moneyOut; //准备消费金额 
} 

/// <summary> 
/// 这个委托用来说明处理吃饭事件的方法的方法头(模式) 
/// </summary> 
public delegate void EatEventHandler(object sender, EatEventArgs e); 

/// <summary> 
/// 引发吃饭事件(EateEvent)的类Master(主人),这个类必须 
/// 1.声明一个名为EatEvent的事件: public event EatEventHandler EatEvent; 
/// 2.通过一个名为OnEatEvent的方法来引发吃饭事件,给那些处理此事件的方法传数据; 
/// 3.说明在某种情形下引发事件呢?在饿的时候。用方法Hungrg来模拟。 
/// </summary> 
public class Master 
{ 
//声明事件 
public event EatEventHandler EatEvent; 

//引发事件的方法 
public void OnEatEvent(EatEventArgs e) 
{ 
if (EatEvent != null) 
{ 
EatEvent(this, e); 
} 
} 

//当主人饿的时候,他会指定吃饭地点和消费金额。 
public void Hungry(String restrauntName, decimal moneyOut) 
{ 
EatEventArgs e = new EatEventArgs(); 
e.restrauntName = restrauntName; 
e.moneyOut = moneyOut; 

Console.WriteLine("主人说:"); 
Console.WriteLine("我饿了,要去{0}吃饭,消费{1}元", e.restrauntName, e.moneyOut); 

//引发事件 
OnEatEvent(e); 
} 
} 

/// <summary> 
/// 类Servant(仆人)有一个方法ArrangeFood(安排食物)来处理主人的吃饭事件 
/// </summary> 
public class Servant 
{ 
public void ArrangeFood(object sender, EatEventArgs e) 
{ 
Console.WriteLine(); 
Console.WriteLine("仆人说:"); 
Console.WriteLine("我的主人, 您的命令是 : "); 
Console.WriteLine("吃饭地点 -- {0}", e.restrauntName); 
Console.WriteLine("准备消费 -- {0}元 ", e.moneyOut); 
Console.WriteLine("好的,正给您安排。。。。。。。。\n"); 
System.Threading.Thread.Sleep( 5000 ); 
Console.WriteLine("主人,您的食物在这儿,请慢用"); 
Console.Read(); 
} 
} 

/// <summary> 
/// 类God安排qinshihuang(秦始皇)的仆人是lisi(李斯),并让李斯的ArrangeFood 
/// 方法来处理qinshihuang的吃饭事件:qinshihuang.EatEvent += new EatEventHandler(lishi.ArrangeFood); 
/// </summary> 
public class God 
{ 
public static void Start() 
{ 
Master qinshihuang = new Master(); 
Servant lishi = new Servant(); 

qinshihuang.EatEvent += new EatEventHandler(lishi.ArrangeFood); 

//秦始皇饿了,想去希尔顿大酒店,消费5000元 
qinshihuang.Hungry("希尔顿大酒店", 5000.0m); 
} 
} 
} 

输出: 

主人说: 
我饿了,要去希尔顿大酒店吃饭,消费5000.0元 

仆人说: 
我的主人, 您的命令是 : 
吃饭地点 -- 希尔顿大酒店 
准备消费 -- 5000.0元 
好的,正给您安排。。。。。。。。 

主人,您的食物在这儿,请慢用



不当之处,欢迎指正。

华为OD机试 - 跳房子I(Java 双机位A卷 100分) 可行的两步组合有 [1, 2] (索引和 0+3=3)、[1, 2] (索引和 0+4=4)、[4, 2] (索引和 1+3=4)、[4, 2] (索引和 1+4=5)、[5, 2] (索引和 2+3=5)、[5, 2] (索引和 2+4=6)。此样例有多种组合满足两回合跳到最后,譬如[-1,9], [2,6],其中[-1,9]的索引和为0+3=3, [2,6]的索引和为1+4=5, 所以索引和最小的步数组合为[-1,9].[3, 2] 和 [1, 4] 都满足和等于 5,且索引和均为 3。 阅读详情

相关推荐

CAN接受和发送失败的原因有哪些---之前调试MCP2515驱动时,数据一直发不出去,三个发送邮箱都被占满.至今未解决,读寄存器-总线错误

0.CAN总线错误分析与解决–讲的最精辟的放在最前面 我们知道CAN总线上的每个节点往总线上发送数据的同时会同时读取总线上的数据,并与自己发送的数据作对比。—CAN仲裁??? CAN总线错误分别有发送和接收错误计数,计数达到一定的累计以后就会产生CAN BUS OFF, 这说明CAN总线上出现了严重的错误。如下图CAN总线产生错误后的状态转换机制 如果出现了BUS OFF,总线上的节点需要做一些动作,例如重启CAN控制器或是重新上电,但是这些都只是一些补救措施,最根本的还是需要找到引起BUS OFF的根源

dianqicyuyan的博客 2万+

C# 根据KeyEventArgs与组合键字符串相互转换

/// 快捷键相关的类 /// </summary> public static class HotKeyInfo { /// <summary> /// 根据KeyEventArgs生成组合键字符串 /// </summary> ...

weixin_34416649的博客 715

工业以太网通讯Profinet协议详解

Profinet是通过西门子控制系统被广泛使用的工业通信协议,是一种较新的,基于以太网的工业通讯协议。

mydatai的专栏 8852

KeyEventArgs中的KeyCode,KeyValue,KeyData的区别

KeyCode: 获取 KeyDown 或 KeyUp 时按下键盘的 Keys 的枚举。KeyValue: 实际上等于 KeyCode, KeyCode是枚举,KeyValue是枚举对应的Integer值。KeyData: 获取 Keys 值,该值表示按下的键的键代码,以及修饰符标志(指示同时按下的 CTRL、SHIFT 和 ALT 键的组合)。所以当同时按下Shift和Enter时:  

Lullaby's Blog 6590

FreeSWITCH编译安装详细文档

本文档详细介绍了在Ubuntu 22.04系统上从源码编译安装FreeSWITCH的完整流程。主要内容包括:1)系统环境准备和依赖库安装;2)关键依赖库spandsp和sofia-sip的编译安装;3)FreeSWITCH源码的特定版本(v1.6.0)编译配置,包括禁用SignalWire模块的配置方法;4)系统服务配置,包括创建专用用户、设置权限以及配置systemd服务文件。文档特别提供了版本控制说明,确保后期能切换到相同的版本环境,并附有详细的命令操作步骤和注意事项。

唯有代码让我痴狂 1369

论文理解【LLM-Agent】——【SkillOpt】Executive Strategy for Self-Evolving Agent Skills

SkillOpt 将 agent skill 从人工或一次性 prompt artifact 转化为可验证、可控、可迁移的文本空间“可训练状态”,通过有界编辑、验证门控、拒绝编辑反馈和 slow/meta update,在不更新模型权重的情况下显著提升多类 agent 任务表现

佚失的诗篇 588

C#小知识(篇章一)

关于自己做项目遇到的知识学习的汇总

qq_43590078的博客 1211

手把手教你用Kokoro-82M-v1.1-zh搭建本地TTS服务(含WebSocket接口)

本文详细介绍了如何使用Kokoro-82M-v1.1-zh模型搭建本地TTS服务,包括环境配置、模型部署、WebSocket接口实现及性能优化。通过实战指南,开发者可以快速掌握本地部署TTS系统的关键技术,提升语音交互应用的开发效率。

weixin_30776273的博客 183

C#键盘事件

1.KeyPressEventArgs类的主要属性(KeyPress事件的一个参数类型)   (1)Handled属性:用来获取或设置一个值,该值指示是否处理过KeyPress事件。   (2)KeyChar属性:用来获取按下的键对应的字符,通常是该键的ASCII码。   2.KeyEventArgs类的主要属性(KeyUp和 KeyDown事件的一个参数)   (1)Alt属性:

Godsight的博客 7479

Xilinx System Generator多速率系统(Multi-Rate Systems)的使用

在本实验练习中,您将学习在System Generator中如何使用多个时钟域有效地实现具有多个数据速率的设计。

白码王子小张的博客 1093

自适应IIR格型滤波器的Matlab实现

概述 在现有的众多抑制窄带干扰的信号处理手段中,时域自适应陷波干扰抑制技术具有实现简单、抗干扰性能好等优点。IIR陷波器按照结构可以分为直接型和格型两种。相比自适应直接型IIR陷波器,自适应格型IIR陷波器不仅可以准确地控制滤波器的陷波频率,也可以准确地调整陷波器的带宽。 传递函数 二阶自适应IIR格型陷波器的传递函数H(z)为: 其中α与陷波带宽有关,β与陷波频率有关;对应的结构如下图所示: Matlab算法实现 ...

剑藏锋的博客 2800

C#事件(event)解析,委托(delegate)与事件(event)的关联

本篇文章非原创,是一位博客园的徐洪军,网名loose_went所写,我从中学到了很多,对于C#的事件(event)的理解也加深了很多,这篇文章值得写的很不错,所以放在这里相当于推广以及留着自己以后也可以看。文章无商用,如果侵犯到原作者的相关权利,我会立马删除 **事件(event):**这个词儿对于初学者来说,往往总是显得有些神秘,不易弄懂。而这些东西却往往又是编程中常用且非常重要的东西。大家都知...

weixin_38778769的博客 658

095、PCIE物理层测试模式:从信号眼图到误码率实战

本文介绍了PCIe物理层测试模式的调试方法和实战经验。重点解析了环回测试、合规性测试和静默模式的应用场景及配置要点,分享了信号眼图分析、误码率测试和接收端验证的实用技巧。作者结合自身调试经历,强调物理层测试对排查信号完整性问题的重要性,建议在量产前进行基础测试,并提醒注意芯片勘误和测试模式切换等易错点。通过合理使用测试模式,可显著提高PCIe链路调试效率,确保物理层稳定可靠。

z534437748的博客 60

c# 事件 event 解析

事件(event),这个词儿对于初学者来说,往往总是显得有些神秘,不易弄懂。而这些东西却往往又是编程中常用且非常重要的东西。大家都知道windows消息处理机制的重要,其实C#事件就是基于windows消息处理机制的,只是封装的更好,让开发者无须知道底层的消息处理机制,就可以开发出强大的基于事件的应用程序来。 先来看看事件编程有哪些好处。 在以往我们编写这类程序中,往往采用等待机制,为了等待某件事...

qq_37657601的博客 222

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

C# 事件(event)解析

转自:http://www.cnblogs.com/michaelxu/archive/2008/04/02/1134217.html#2168843 大家都知道windows消息处理机制的重要,其实C#事件就是基于windows消息处理机制的,只是封装的更好,让开发者无须知道底层的消息处理机制,就可以开发出强大的基于事件的应用程序来。 在以往我们编写这类程序中,往往采用等待机制,为了等待某件

白永辉的专栏 676

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

C#事件(event)解析[转]

    事件(event),这个词儿对于初学者来说,往往总是显得有些神秘,不易弄懂。而这些东西却往往又是编程中常用且非常重要的东西。大家都知道windows消息处理机制的重要,其实C#事件就是基于windows消息处理机制的,只是封装的更好,让开发者无须知道底层的消息处理机制,就可以开发出强大的基于事件的应用程序来。     先来看看事件编程有哪些好处。    在以往我们编写这类程序中,往往采用等

某任的专栏 643

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

上一篇: C# 自定义异常的总结
下一篇: 详谈Delegate (一)
雪岢奇
博客等级 码龄17年 310粉丝 60原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值