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: ...
随机推荐
- Python基础 语法特别注意笔记(和Java相比)
Python变量和数据类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 ...
- MinerConfig.java 爬取配置类
MinerConfig.java 爬取配置类 package com.iteye.injavawetrust.miner; import java.util.List; /** * 爬取配置类 * @ ...
- 深入认识AsyncTask
1.概述 在android开发中是采用单线程模型,主线程通常称为UI线程,由于UI线程的操作不是线程安全的,因此android规定有关更新界面的操作必须在主线程中进行,其他线程直接报错. 如果我们把所 ...
- 【Android 应用开发】Android - 按钮组件详解
总结了Android中常用的按钮用法 示例源码下载地址 : -- CSDN : http://download.csdn.net/detail/han1202012/6852091 -- GitHu ...
- 总结C语言在嵌入式开发中应用的知识点(文件数据的加密与解密)
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255) ...
- SharePoint 2013配置启用搜索服务
1.安装完毕SharePoint 2013,新建网站集,点击搜索,出现如下错误(因为没配置,别激动). 2.尝试启动服务器场中的服务之SharePoint Server Search,提示新建搜索应用 ...
- IOS空数据页面,网络加载失败以及重新登陆View的封装(不需要继承)
一.问题 对于B2C和B2B项目的开发者,可能会有一个订单列表为空,或者其他收藏页面为空,用户token失效,判断用户要重新登陆,以及后台服务错误等提示.本篇课文,看完大约10分钟. 原本自己不想写空 ...
- 重定向和servlet生命周期
重定向(1)什么是重定向服务器通知浏览器向一个新的地址发送请求.注:可以发送一个302状态码和一个Location消息头.(该消息头包含了一个地址,称之为重定向地址),浏览器收到之后,会立即向重定向地 ...
- 使用 Helm - 每天5分钟玩转 Docker 容器技术(163)
Helm 安装成功后,可执行 helm search 查看当前可安装的 chart. 这个列表很长,这里只截取了一部分.大家不禁会问,这些 chart 都是从哪里来的? 前面说过,Helm 可以像 a ...
- Core Animation简介
一.Core Animation简介 * Core Animation,中文翻译为核心动画,它是一组非常强大的动画处理API,使用它能做出非常炫丽的动画效果,而且往往是事半功倍.也就是说,使用少量的代 ...