从退出应用到lol自定义游戏退出eventhandler,还能怎么玩

[转载]PropertyChanged&事件
在.NET平台上,数据绑定是一项令人十分愉快的技术。利用数据绑定能减少代码,简化控制逻辑。
通常,可以将某个对象的一个属性绑定到一个可视化的控件上,当属性值改变时,控件上的显示数据也随之发生变化。要实现这一功能,只需要为自定义对象实现
INotifyPropertyChanged 接口即可。此接口中定义了 PropertyChanged
事件,我们只需在属性值改变时触发该事件即可。下面的例子说明如何绑定如何自定义可用于数据绑定的对象:
假设我们有自定义对象 CustomizedObject 和窗体上的 Label 控件 label1,想要将
CustomizedObject 的 Date 属性和 label1.Text 关联起来,Date
属性值会在程序运行过程当中发生变化(例如点击 Button 控件 button1),并且直接反映在 label1.Text
上。下面的代码可以实现上述功能:
using System.Windows.F
namespace WindowsFormsApplication1
&&& public
partial class Form1 : Form
private CustomizedObject myO
public Form1()
&&&&&&&&&&&
InitializeComponent();
&&&&&&&&&&&
// 初始化CustomizedObject对象
&&&&&&&&&&&
myObject = new CustomizedObject { Date = DateTime.Now };
&&&&&&&&&&&
// 绑定对象的属性到label1
&&&&&&&&&&&
label1.DataBindings.Add("Text", myObject, "Date");
private void button1_Click(object sender, EventArgs e)
&&&&&&&&&&&
// 点击按钮改变对象的属性值
&&&&&&&&&&&
myObject.Date = myObject.Date.AddDays(1);
&&& // 自定义对象
CustomizedObject 并实现 INotifyPropertyChanged 接口
&&& public
class CustomizedObject : INotifyPropertyChanged
private DateTime dateV
// 自定义一个 Date 属性
public DateTime Date
&&&&&&&&&&&
get { return dateV }
&&&&&&&&&&&
&&&&&&&&&&&
&&&&&&&&&&&&&&&
dateValue =
&&&&&&&&&&&&&&&
NotifyPropertyChanged("Date");
&&&&&&&&&&&
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyC
// 添加一个触发 PropertyChanged 事件的通用方法
protected virtual void NotifyPropertyChanged(string
propertyName)
&&&&&&&&&&&
if (PropertyChanged != null)
&&&&&&&&&&&
&&&&&&&&&&&&&&&
PropertyChanged(this, new
PropertyChangedEventArgs(propertyName));
&&&&&&&&&}
#endregion
其实从上面的例子中可以学习到如何自定义事件,这在开发控件时十分有用且非常重要。通过观察
INotifyPropertyChanged 接口可以知道它内部有一个成员,那就是:
event PropertyChangedEventHandler PropertyC
而其中的 PropertyChangedEventHandler 实质上是一个委托,明白了这一点就可以自定义事件了。
现在,开始为 Form1 自定义事件 DateChanged
(事件一般是定义在控件或组件中的,这里只是为了说明其过程而没有重新定义一个控件),首先需要一个事件参数类型:
public class DateChangedEventArgs : EventArgs
&&& public
DateTime OldValue { }
&&& public
DateTime NewValue { }
声明一个事件处理委托
public delegate void DateChangedHandler(object sender,
DateChangedEventArgs e);
我们可以将事件直接添加到Form1的定义中,但有时为了代码的通用性,可以将事件封装到一个接口中,例如:
public interface IDateChanged
DateChangedHandler DateC
然后我们为Form1实现 IDateChanged 接口,并在button1点击时触发该事件。以下是完整代码:
using System.Windows.F
namespace WindowsFormsApplication1
&&& public
partial class Form1 : Form, IDateChanged
private CustomizedObject myO
public Form1()
&&&&&&&&&&&
InitializeComponent();&&&&&&&&&&&
&&&&&&&&&&&
// 初始化CustomizedObject对象
&&&&&&&&&&&
myObject = new CustomizedObject { Date = DateTime.Now };
&&&&&&&&&&&
// 绑定对象的属性到label1
&&&&&&&&&&&
label1.DataBindings.Add("Text", myObject, "Date");
&&&&&&&&&&&
// 添加 DateChanged 事件的处理逻辑
&&&&&&&&&&&
this.DateChanged += new DateChangedHandler(Form1_DateChanged);
private void Form1_DateChanged(object sender, DateChangedEventArgs
&&&&&&&&&&&
string message = string.Format(
&&&&&&&&&&&&&&&
"DateChanged event triggered!nOldValue: {0}nNew Value: {1}",
&&&&&&&&&&&&&&&
e.OldValue,
&&&&&&&&&&&&&&&
e.NewValue);
&&&&&&&&&&&
MessageBox.Show(message);
private void button1_Click(object sender, EventArgs e)
&&&&&&&&&&&
// 点击按钮改变对象的属性值并触发 DateChanged 事件
&&&&&&&&&&&
DateChangedEventArgs ev = new DateChangedEventArgs
&&&&&&&&&&&
&&&&&&&&&&&&&&&
OldValue = myObject.Date,
&&&&&&&&&&&&&&&
NewValue = myObject.Date.AddDays(1)
&&&&&&&&&&&
&&&&&&&&&&&
myObject.Date = ev.NewV
&&&&&&&&&&&
DateChangedMethod(ev);
#region IDateChanged Members
public event DateChangedHandler DateC
// 添加一个触发 DateChanged 事件的通用方法
protected virtual void DateChangedMethod(DateChangedEventArgs
&&&&&&&&&&&
if (DateChanged != null)
&&&&&&&&&{
&&&&&&&&&&&&&&&
DateChanged(this, e);
&&&&&&&&&&&
#endregion
&&& // 自定义对象
CustomizedObject 并实现 INotifyPropertyChanged 和 IDateChanged 接口
&&& public
class CustomizedObject : INotifyPropertyChanged
private DateTime dateV
// 自定义一个 Date 属性
public DateTime Date
&&&&&&&&&&&
get { return dateV }
&&&&&&&&&&&
&&&&&&&&&&&
&&&&&&&&&&&&&&&
dateValue =
&&&&&&&&&&&&&&&
NotifyPropertyChanged("Date");
&&&&&&&&&&&
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyC
// 添加一个触发 PropertyChanged 事件的通用方法
protected virtual void NotifyPropertyChanged(string
propertyName)
(PropertyChanged != null)
&&&&&&&&&&&
&&&&&&&&&&&&&&&
PropertyChanged(this, new
PropertyChangedEventArgs(propertyName));
&&&&&&&&&&&
#endregion
DateChanged 事件委托
&&& public
delegate void DateChangedHandler(object sender,
DateChangedEventArgs e);
用于封装事件的接口
&&& public
interface IDateChanged
event DateChangedHandler DateC
DateChanged 事件参数
&&& public
class DateChangedEventArgs : EventArgs
public DateTime OldValue { }
public DateTime NewValue { }
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。Android事件总线还能怎么玩?顾名思义,AndroidEventBus (&&,关于我为什么要写这个库请参考《》)是一个Android平台的事件总线框架,它简化了Activity、Fragment、Service等组件之间的交互,很大程度上降低了它们之间的耦合,使我们的代码更加简洁,耦合性更低,提升了我们的代码质量。但它能做的却不仅限于这些。经过定制,它能完成很多有意思的功能,那么究竟该怎么做呢?就让我们一起往下看吧。不堪回首的痛首先,让我们先来看看这么一个场景:你是否在开发的过程中遇到过从Activity-A跳转到Activity-B,然后需要在Activity-B处理完某些工作之后回调Activity-A中的某个函数,但Activity又不能手动创建对象来设置一个Listener的情况?或者遇到在某个Service中更新Activity或Fragment中的界面等组件之间的交互问题……一经思考,你会发现Android中的Activity、Fragment、Service之间的交互是比较麻烦的,可能我们第一想到的是使用广播接收器来在它们之间进行交互。如上文所说,在Activity-B中发一个广播,在Activity-A中注册一个广播接收器来接收该广播。但使用广播接收器稍显麻烦,如果你要将一个实体类当作数据在组件之间传递,那么该实体类还得实现序列化接口,这个成本实在有点高!如代码1所示。class ActivityA extends Activity {
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ActivityA中注册广播接收器
registerReceiver(new BroadcastReceiver() {
@Overridepublic void onReceive(Context context, Intent intent) {
User person = intent.getParcelableExtra("user") ;
}, new IntentFilter("my_action")) ;
// ActivityB中发布广播
class ActivityB extends Activity {
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 发布广播
Intent intent
= new Intent("my_
intent.putExtra("user", new User("mr.simple")) ;
sendBroadcast(intent);
// 实体类需要实现序列化
class User implements Parcelable {
public User(String aName) {
// 代码省略
@Overridepublic void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
1234567891011121314151617181920212223242526272829303132333435363738代码1是不是有很麻烦的感觉?我们再来看一个示例,在开发过程中,我们经常要在子线程中做一些耗时操作,然后将结果更新到UI线程,除了AsyncTask之外,Thread加Handler是我们经常用的手段。如代码2所示。
class MyActivity extends Activity {
Handler mHandler = new Handler () {
public void handleMessage(android.os.Message msg) {
if ( msg.what == 1 ) {
User user = (User)msg.
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// code ......
new Thread(
new Runnable() {
public void run() {
User newUser = new User("simple") ;
Message msg = mHandler.obtainMessage() ;
msg.what = 1 ;
msg.obj = newU
mHandler.sendMessage(msg) ;
}).start();
123456789101112131415161718192021222324252627代码2是不是依然相当麻烦?当然你也可以使用AsyncTask来简化操作,但AsyncTask的几个泛型参数让你的代码看起来并不那么简洁,因此GitHub上出现了TinyTask、SimpleTask这些开源库来简化AsyncTask的使用。而这些,使用AndroidEventBus都可以很好地解决!下面就让我们来领悟一下AndroidEventBus的强大魅力吧。初见AndroidEventBus使用AndroidEventBus简单概括只有三个步骤:将对象注册到AndroidEventBus中;使用@Subcriber标注订阅函数(只能有一个参数);通过post函数发布事件。对应的简单序列图如下 :EventBusEventBus订阅对象订阅对象注册发布事件查找订阅对象订阅方法执行在具体的线程模型执行订阅方法注册订阅对象注册订阅对象,如代码3所示。public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 将对象注册到事件总线中, ****** 注意要在onDestory中进行注销 ****
EventBus.getDefault().register(this);
@Overrideprotected void onDestroy() {
super.onDestroy();
// ****** 不要忘了进行注销 ****
EventBus.getDefault().unregister(this);
// 代码省略
} 12345678910111213141516代码3在onCreate中注册之后,MainActivity就可以添加订阅函数来接收消息了。需要注意的是在onDestory中需要将MainActivity从事件总线中注销。通过AndroidEventBus你可以去除Activity、Fragment、Service等组件的回调,减少了耦合,简化了代码。事件订阅函数事件订阅需要使用@Subscriber注解进行标识,且订阅函数的参数必须为一个。事件总线凭借参数类型和@Subscriber注解的tag值来标识订阅函数的唯一性。当用户发布事件时,总线库会根据事件类型和tag来查找符合要求的订阅函数,并且将这些订阅函数执行在对应的线程中。我们先来看看代码4的订阅函数示例。public class MainActivity extends Activity {// 代码省略
@Subcriber(tag = "csuicide")
private void csuicideMyself(String msg) {
@Subcriber(mode = ThreadMode.MAIN)
private void toastMsgFromEvent(String msg) {
@Subcriber(tag = "async", mode = ThreadMode.ASYNC)
private void executeAsync(final String msg) {
// 代码省略
1234567891011121314151617代码4在代码4中,我们为MainActivity添加了以下三个订阅函数:csuicideMyself:该订阅函数执行在主线程,接收事件的类型为String,tag为csuicide。当用户发布一个事件类型为String,且tag为csuicide的事件时将会触发该方法。toastMsgFromEvent:该订阅函数也是执行在主线程,事件类型为String,且tag为默认。当用户发布一个事件类型为String,且tag为默认的事件时将会触发该方法。executeAsync:该订阅函数也是执行在一个异步线程,事件类型为String,且tag为async。当用户发布一个事件类型为String,且tag为async的事件时将会触发该方法。&从上述的描述中我们可以知道,事件接收函数主要有两个约束:事件类型和tag(类似于Intent中的Action)。添加tag是因为在事件类型一样时,如果投递一个消息,那么单纯以事件类型(例如String)作为投递依据,那么多个参数为String的订阅函数将会被触发,这极大地降低了灵活性。发布事件// 参数 1 为事件类型,无 tag
EventBus.getDefault().post("这是一个执行在异步线程的事件");
// 参数 1 为事件类型,参数 2 为 tag,tag 的类型为 String,类似 Intent 的 Action
EventBus.getDefault().post("这是一个执行在异步线程的事件", "async");1234发布事件时可以构造任意类型的事件,如果没有tag则该参数可以省略。发布事件后,AndroidEventBus会根据事件类型和tag到已注册的订阅对象中查找符合要求的订阅函数,例如投递的第二个事件类型为String、tag为async,那么在MainActivity中符合要求的订阅函数就是:@Subcriber(tag = "async", mode = ThreadMode.ASYNC)
private void executeAsync(final String msg) {
1234AndroidEventBus的ThreadMode在上述代码中有一段代码是这样的:@Subcriber(mode = ThreadMode.MAIN)
private void toastMsgFromEvent(String msg) {
} 123这个mode可是大有来头,它指定这个事件接收函数执行在哪个线程中。具体有如下三个选项:ThreadMode.MAIN,事件接收函数执行在UI线程;ThreadMode.POST,事件在哪个线程发布,接收函数就执行在哪个线程;ThreadMode.ASYNC,事件执行在一个独立的异步线程中。图1中,事件接收函数就执行在异步线程。通过这几个线程模型,我们就可以定制接收函数的执行线程。这样我们就可以使用AndroidEventBus做很多事了。比如发布一个事件,在这个事件接收函数中进行耗时操作;或下载图片、进行HTTP请求、I/O操作等,以及替换Thread、AsyncTask等组件。不过,AndroidEventBus的功能远不止于此,下面我们就看看如何进行更高端的操作。&图1 接收函数执行在异步线程中还可以怎么玩?退出应用的另类实现在Android应用开发中,有些情况下我们需要可以直接退出程序。但问题是,回退栈中含有其他的Activity存在,直接使用返回键并不能退出应用。此时我们常见的做法是再自定义一个Application子类,在子类中维护一个Activity的列表,然后在进入Activity时,将Activity添加到列表中,在Activity销毁之前将自己从Application子类的列表中移除。在需要退出应用时遍历Application子类的Activity列表,然后调用每个Activity的finish函数。那我们看看AndroidEventBus怎么实现这个功能。如代码5所示。public class CsuicideActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 将对象注册到事件总线中, ****** 注意要在onDestory中进行注销 ****
EventBus.getDefault().register(this);
@Overrideprotected void onDestroy() {
super.onDestroy();
// ****** 不要忘了进行注销 ****
EventBus.getDefault().unregister(this);
@Subcriber(tag = "csuicide")
private void csuicideMyself(String msg) {
123456789101112131415161718代码5代码5中,我们定义一个CsuicideActivity在onCreate中注册该Activity对象,在onDestroy中注销,还添加了一个csuicideMyself的订阅函数。所有的Activity类可以继承自CsuicideActivity。当需要退出应用时,直接发布一个类型为String、tag为csuicide的事件即可。这样所有的Activity就会触发csuicideMyself,而该函数中又调用了finish方法,因此所有的Activity都将退出,通过这种方式就完成了应用退出。自定义事件处理器 ( EventHandler )AndroidEventBus在设计之初就考虑到了可扩展性,主要可扩展的地方就是订阅函数的搜索策略,具体可以调用EventBus.getDefualt().setMatchPolicy(MatchPolicy policy)来实现策略替换。另一个比较重要的扩展就是事件处理器EventHandler,用户可以通过setter函数来设置三个事件处理器。如代码6所示。 /**
* 设置执行在UI线程的事件处理器
* @param handler
UI线程事件处理器
*/public void setUIThreadEventHandler(EventHandler handler) {
mDispatcher.mUIThreadEventHandler =
* 设置执行在post线程的事件处理器
* @param handler 事件在哪个线程投递,事件就执行在哪个线程的事件处理器
*/public void setPostThreadHandler(EventHandler handler) {
mDispatcher.mPostThreadHandler =
* 设置执行在异步线程的事件处理器
* @param handler 异步线程事件处理器
*/public void setAsyncEventHandler(EventHandler handler) {
mDispatcher.mAsyncEventHandler =
} 123456789101112131415161718192021代码6EventHandler的接口定义如代码7所示,只需实现handleEvent即可,然后将该实现注入到EventBus即可。/**
* 事件处理接口,处理事件的抽象
*/public interface EventHandler {/**
* 处理事件
* @param subscription 订阅对象
* @param event 待处理的事件
*/void handleEvent(Subscription subscription, Object event);
1234567891011代码7默认有DefaultEventHandler、UIThreadEventHandler、AsyncEventHandler三个实现:DefaultEventHandler:事件在哪个线程发布,就将事件接收函数执行在哪个线程;UIThreadEventHandler:将事件接收函数执行在UI线程;AsyncEventHandler:将事件接收函数执行在异步线程。下面我们以自定义异步事件处理器,也就是AsyncEventHandler,通过实现EventHandler接口,将事件处理函数执行在一个线程池中,从而实现图片下载的功能。如代码8所示。public class ThreadPoolHandler implements EventHandler {
ExecutorService mExecutorService = Executors.newFixedThreadPool(3);
EventHandler mHandler = new DefaultEventHandler();
@Overridepublic void handleEvent(final Subscription subscription, final Object event) {
mExecutorService.submit(new Runnable() {
@Overridepublic void run() {
mHandler.handleEvent(subscription, event);
12345678910111213代码8然后通过如下代码将ThreadPoolEventHandler注入到AndroidEventBus中:// 自定义的异步事件处理器,使用线程池
EventBus.getDefault().setAsyncEventHandler(new ThreadPoolHandler());
12再在订阅对象中添加代码9所示的订阅方法 :@Subcriber(tag = "download", mode = ThreadMode.ASYNC)
private void downloadImage(final String imageUrl) {
HttpURLConnection urlConnection = null;
final URL url = new URL(imageUrl);
urlConnection = (HttpURLConnection) url.openConnection();
final Bitmap bmp = BitmapFactory.decodeStream(urlConnection.getInputStream());
// 将Bitmap投递给ImageView之类的工作
} catch (IOException e) {
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
123456789101112131415代码9最后,当需要下载图片时,通过post发布一个参数为String类型、tag为download的事件即可执行downloadImage函数,这个函数将执行在线程池中,我们的简易ImageLoader就这么实现了。&&图2 图片下载中图3 图片下载完成当然,由于AndroidEventBus的高度定制化,我们还可以通过AndroidEventBus来实现各种各样的功能,它到底还能怎么玩,我就不做过多的演示了,开发者可以充分发挥自己的聪明才智和想象力。
阅读(...) 评论()Sharepoint怎么开发EventHandler-CSDN论坛_百度知道关于反射从EventInfo中反射出EventHandler
[问题点数:40分,结帖人jy]
关于反射从EventInfo中反射出EventHandler
[问题点数:40分,结帖人jy]
不显示删除回复
显示所有回复
显示星级回复
显示得分回复
只显示楼主
2010年 总版技术专家分年内排行榜第一2009年 总版技术专家分年内排行榜第一
2011年 总版技术专家分年内排行榜第二
2010年11月 总版技术专家分月排行榜第二2010年9月 总版技术专家分月排行榜第二2010年8月 总版技术专家分月排行榜第二
2010年7月 总版技术专家分月排行榜第三
2010年11月 总版技术专家分月排行榜第二2010年9月 总版技术专家分月排行榜第二2010年8月 总版技术专家分月排行榜第二
2010年7月 总版技术专家分月排行榜第三
本帖子已过去太久远了,不再提供回复功能。下次自动登录
现在的位置:
& 综合 & 正文
WPF:使用RoutedPropertyChangedEventArgs和RoutedPropertyChangedEventHandler类型
为了方便常见的针对属性值改变的路由事件,WPF提供了定义此类路由事件的辅助类型。分别是泛型RoutedPropertyChangedEventHandler委托来定义此类路由事件的委托类型。另一个类型是RoutedPropertyChangedEventArgs泛型类型来定义此类路由事件的自定义EventArgs。
它们的使用非常方便,泛型类型参数就是相应属性值的类型。另外RoutedPropertyChangedEventArgs还改写了RoutedEventArgs.InvokeEventHandler方法,这样执行更有效率。
比如定义一个路由事件IdChanged(代表Id属性改变),使用RoutedPropertyChangedEventHandler指定委托类型:
class a : UIElement
#region 路由事件IdChanged
//注册路由事件
public static readonly RoutedEvent IdChangedEvent = EventManager.RegisterRoutedEvent("IdChanged",
RoutingStrategy.Bubble, typeof(RoutedPropertyChangedEventHandler&int&), typeof(a));
//CLR事件包装
public event RoutedEventHandler IdChanged
add { AddHandler(IdChangedEvent, value); }
remove { RemoveHandler(IdChangedEvent, value); }
#endregion
接下来就是定义Id依赖属性,在依赖属性的属性值改变方法中(PropertyMetadata.PropertyChangedCallback)运行路由事件,使用RoutedPropertyChangedEventArgs:
class a : UIElement
#region 依赖属性Id
//注册依赖属性
public static readonly DependencyProperty IdProperty =
DependencyProperty.Register("Id", typeof(int), typeof(a),
new PropertyMetadata((int)0,
new PropertyChangedCallback(OnIdChanged)));
//CLR属性包装
public int Id
get { return (int)GetValue(IdProperty); }
set { SetValue(IdProperty, value); }
//静态OnChanged
private static void OnIdChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
a target = (a)d;
int oldId = (int)e.OldV
int newId = target.Id;
target.OnIdChanged(oldId, newId);
//非静态OnChanged
protected virtual void OnIdChanged(int oldId, int newId)
//调用路由事件
RaiseEvent(new RoutedPropertyChangedEventArgs&int&(oldId, newId));
#endregion
&&&&推荐文章:
【上篇】【下篇】}

我要回帖

更多关于 lol自定义怎么退出 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信