c# 事件和EventManager
事件
基本用法
关键字event,声明格式为:
public event <委托类型> <事件对象>
事件的处理方法:适用于该委托的方法
数据的触发:
- 绑定同类事件,绑定时,可以绑定新的委托对象(更容易理解的写法),也可以隐式转换,直接绑定方法。
- 手动触发
例子:
//新建一个EventArgs类的子类用于处理
class MessageArrivedEventArgs : EventArgs
{
private string message;
public string Message { get => message; }
public MessageArrivedEventArgs()
{
message = "No message sent";
}
public MessageArrivedEventArgs(string newMessage)
{
message = newMessage;
}
}
//事件的处理方法
class Display
{
internal void DisplayMessage(object sender, MessageArrivedEventArgs e)
{
Console.WriteLine("Message arrived from:" + ((Connection)sender).Name);
Console.WriteLine("Message text:" + e.Message);
}
}
class Connection
{
//事件声明
//EventHandler是系统自建的用于处理事件的委托
public event EventHandler<MessageArrivedEventArgs> MessageArrived;
public String Name { get; set; }
private Timer pollTimer;
public static Random random = new Random();
public Connection()
{
pollTimer = new Timer(100);
//达到时间间隔时用CheckForMessage方法处理事件。(类型EvenHandler<MessageArrivedArgs>已经隐式转换)
pollTimer.Elapsed += CheckForMessage;
}
public void Connect() => pollTimer.Start();
public void Disconnect() => pollTimer.Stop();
private void CheckForMessage(object sender, ElapsedEventArgs e)
{
Console.WriteLine("Checking for new messages.");
if (random.Next(9) == 0)
{
//触发事件。
MessageArrived?.Invoke(this, new MessageArrivedEventArgs(DateTime.Now.ToLongTimeString()));
}
}
}
//主程序
class MainControll
{
static void Main(string[] args)
{
Connection connection = new Connection();
Connection connectionB = new Connection();
connection.Name = "First connection";
connectionB.Name = "Second connection";
Display display = new Display();
//事件触发时用DisplayMessage方法处理事件
connection.MessageArrived += display.DisplayMessage;
connectionB.MessageArrived += display.DisplayMessage;
connection.Connect();
connectionB.Connect();
System.Threading.Thread.Sleep(2000);
ReadKey();
}
}
匿名委托方法
当一个事件处理方法仅在一处调用时,可以干脆写成匿名方法,比如,如果上述示例代码中的DisplayMessage仅调用一次的话,可以写成以下形式:
connection.MessageArrived += delegate(Conection sender,MessageArrivedEventArgs e)
{
Console.WriteLine("Message arrived from:" + ((Connection)sender).Name);
Console.WriteLine("Message text:" + e.Message);
}
写成匿名方法,可以更加直观。
EventHandler
分为默认的EventHandler和带有类型的EventHandler,后者可以指定事件实参的类型。
EventManager
EventManager类在大型应用开发中可以非常好用的来设置全局事件,起到类似切面编程的效果,比如,为一个已经基本开发完毕的应用添加权限控制功能,就可以用到。该类只有五个方法:
public static class EventManager
{
//
// 摘要:
// 为已注册到事件系统的路由事件返回标识符。
//
// 返回结果:
// 包含注册对象的 System.Windows.RoutedEvent 类型的数组。
public static RoutedEvent[] GetRoutedEvents();
//
// 摘要:
// 查找使用所提供的所有者类型注册的事件的所有路由事件标识符。
//
// 参数:
// ownerType:
// 从其开始搜索的类型。搜索中包含基类。
//
// 返回结果:
// 如果找到任何匹配项,则返回匹配路由事件标识符的数组;否则返回 null。
public static RoutedEvent[] GetRoutedEventsForOwner(Type ownerType);
//
// 摘要:
// 为特定路由事件注册类处理程序。
//
// 参数:
// classType:
// 声明类处理的类的类型。
//
// routedEvent:
// 要处理的事件的路由事件标识符。
//
// handler:
// 对类处理程序实现的引用。
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
public static void RegisterClassHandler(Type classType, RoutedEvent routedEvent, Delegate handler);
//
// 摘要:
// 使用处理事件数据已标记为已处理的事件的选项,为特定路由事件注册类处理程序。
//
// 参数:
// classType:
// 声明类处理的类的类型。
//
// routedEvent:
// 要处理的事件的路由事件标识符。
//
// handler:
// 对类处理程序实现的引用。
//
// handledEventsToo:
// 如果即使已将路由事件的参数标记为已处理时也调用此类处理程序,则为 true;如果保留不对任何标记为已处理的事件调用处理程序的默认行为,则为 false。
public static void RegisterClassHandler(Type classType, RoutedEvent routedEvent, Delegate handler, bool handledEventsToo);
//
// 摘要:
// 向 Windows Presentation Foundation (WPF) 事件系统注册新的路由事件。
//
// 参数:
// name:
// 路由事件的名称。该名称在所有者类型中必须是唯一的,并且不能为 null 或空字符串。
//
// routingStrategy:
// 作为枚举值的事件的路由策略。
//
// handlerType:
// 事件处理程序的类型。该类型必须为委托类型,并且不能为 null。
//
// ownerType:
// 路由事件的所有者类类型。该类型不能为 null。
//
// 返回结果:
// 新注册的路由事件的标识符。现在可将该标识符对象存储为类中的静态字段,然后将其用作将处理程序附加到事件的方法的参数。路由事件标识符也用于其他事件系统 APIs。
public static RoutedEvent RegisterRoutedEvent(string name, RoutingStrategy routingStrategy, Type handlerType, Type ownerType);
}
官方文档非常详细了,可以看到,除了查询由Manager管理的事件,主要形式功能的方法有两个
- RegisterClassHandler 最关键的方法之一,前三个参数为类型,路由事件,事件处理委托,最后一个可缺省参数决定是否处理已经被处理过的路由事件。
- RegisterRoutedEvent 向WPF中注册自定义路由事件的方法。
对于RegisterClassHandler的有效使用,可以大大提高应用的开发效率。就拿扫雷这款游戏而言,扫雷的界面上每一个各自都是Button,如果我们对每个Button的Click事件都进行分别处理,是一件没有必要的事情。而使用该方法,我们可以对所有Button控件来进行处理。
下面举一个全局处理权限的例子:
EventManager.RegisterClassHandler(typeof(TabControl), Selector.SelectionChangedEvent, new RoutedEventHandler(DisableTabControl));
针对全局的TabControl空间的SelectionChangedEvent去进行处理,处理方法如下,如果是在C# 6环境下,还可以写的再简单点。
private void DisableTabControl(object sender, RoutedEventArgs e)
{
if (sender is TabControl)
{
var tabControl = sender as TabControl;
foreach (var item in tabControl.Items)
{
if (item is TabItem)
{
var tabItem = item as TabItem;
var valueGot = GlobalParams.FunctionDictionary.TryGetValue(tabItem.Header.ToString(), out string auth);
if (valueGot && !GlobalParams.AuthSet.Contains(auth))
{
tabItem.Visibility = Visibility.Hidden;
if (tabItem == tabControl.SelectedItem)
{
tabControl.SelectedItem = null;
}
}
}
}
}
}
c# 事件和EventManager的更多相关文章
- 自定义事件类EventManager (TS中...args的使用例子)
一个自定义事件类 初衷是使用Egret的事件有两点比较麻烦 1 在事件处理函数时,需要从e中获取data hander(e:egret.Event){ let data = e.data; } 2 ...
- Unity3D C#事件管理:EventManager
原文地址:http://bbs.9ria.com/thread-153258-1-1.html 原project地址:https://github.com/djandrew/UnityEventMan ...
- WPF:自定义路由事件的实现
路由事件通过EventManager,RegisterRoutedEvent方法注册,通过AddHandler和RemoveHandler来关联和解除关联的事件处理函数:通过RaiseEvent方法来 ...
- phalcon: plugin 结合Manager事件管理、dispatcher调度控制器 监听sql日志记录或其他拦截出来
可能用到的类 phalcon\mvc\use\plugin Phalcon\Mvc\Dispatcher as MvcDispatcher Phalcon\Events\Manager as Even ...
- ExtJs的事件机制Event(学员总结)
一.事件的三种绑定方式 1.HTML/DHTML 在标签中直接增加属性触发事件 [javascript] view plaincopy <script type="text/javas ...
- 【cocos2d-js公文】十七、事件分发机制
简单介绍 游戏开发中一个非常重要的功能就是交互,假设没有与用户的交互.那么游戏将变成动画,而处理用户交互就须要使用事件监听器了. 总概: 事件监听器(cc.EventListener) 封装用户的事件 ...
- ExtJS框架基础:事件模型及其常用功能
前言 工作中用ExtJS有一段时间了,Ext丰富的UI组件大大的提高了开发B/S应用的效率.虽然近期工作中天天都用到ExtJS,但很少对ExtJS框架原理性的东西进行过深入学习,这两天花了些时间学习了 ...
- 【cocos2d-js官方文档】事件分发监听机制(摘录)
简介 游戏开发中一个很重要的功能就是交互,如果没有与用户的交互,那么游戏将变成动画,而处理用户交互就需要使用事件监听器了. 总概: 事件监听器(cc.EventListener) 封装用户的事件处理逻 ...
- cocos2d JS 监听键盘触摸响应事件(cc.EventListener.KEYBOARD)
除了可以监听键盘按键,还可以是终端设备的各个菜单键,都能使用同一个监听器来进行处理. //给statusLabel绑定键盘事件 cc.eventManager.addListener({ event: ...
随机推荐
- 【一天一道LeetCode】#65. Valid Number
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Validat ...
- android官方技术文档翻译——aar 格式
本文译自androd官方技术文档<AAR Format>,原文地址:http://tools.android.com/tech-docs/new-build-system/aar-form ...
- Python进阶 函数式编程和面向对象编程等
函数式编程 函数:function 函数式:functional,一种编程范式.函数式编程是一种抽象计算机的编程模式. 函数!= 函数式(如计算!=计算机) 如下是不同语言的抽象 层次不同 高阶函数: ...
- Android 5.0 SEAndroid下如何获得对一个内核节点的访问权限
-9]* u:object_r:tty_device:s0 # We add here /dev/wf_bt u:object_r:wf_bt_device:s0 wf_bt ...
- 《java入门第一季》之面向对象(内部类到底在哪里?)
/* 内部类概述: 把类定义在其他类的内部,这个类就被称为内部类. 举例:在类A中定义了一个类B,类B就是内部类. 内部的访问特点: A:内部类可以直接访问外部类的成员,包括私有. B:外部类要访问内 ...
- iOS开发经验相关知识
一. iPhone Size 手机型号 屏幕尺寸 iPhone 4 4s 320 * 480 iPhone 5 5s 320 * 568 iPhone 6 6s 375 * 667 iphone 6 ...
- mysql进阶(十一)外键在数据库中的作用
MySQL外键在数据库中的作用 MySQL外键的目的是控制存储在外键表中的数据,使两张表形成关联,是MySQL数据库中非常重要的组成部分,值得我们去深入了解.那么,MySQL外键究竟起到哪些作用呢?下 ...
- 为神马精确Sprite的碰撞形状不通过简单的放大Sprite的尺寸来解决?
原因是SoftBodyDrawNode的绘制代码中已经没有完整的,一体化的(incorporate)缩放,旋转或者甚至是精灵的位置(scale,rotation,or even the sprite' ...
- Android开发技巧——自定义单选或多选的ListView
这篇其实应该是属于写自定义单选或多选的ListView的基础教程,无奈目前许多人对此的实现大多都绕了远路,反而使得这正规的写法倒显得有些技巧性了. 本文原创,转载请注明在CSDN上的出处: http: ...
- 初探linux子系统集之led子系统(一)
就像学编程第一个范例helloworld一样,学嵌入式,单片机.fpga之类的第一个范例就是点亮一盏灯.对于庞大的linux系统,当然可以编写一个字符设备驱动来实现我们需要的led灯,也可以直接利用g ...