WPF自定義路由事件的實(shí)例教程
路由事件模型
傳統(tǒng)的簡單事件模型中,在消息激發(fā)是將消息通過事件訂閱的然后交給事件的相應(yīng)者,事件的相應(yīng)者使用事件的處理器來做出相應(yīng),這樣就存在一個(gè)問題,用戶控件內(nèi)部的事件就不能被外界訂閱,因?yàn)槭录乃拗鞅仨毮軌蛑苯釉L問到事件的響應(yīng)者。
路由事件的事件擁有者和事件的相應(yīng)者之間則沒有直接的顯式訂閱關(guān)系,事件的擁有者則只負(fù)責(zé)激發(fā)事件,事件將有誰相應(yīng)它并不知道,事件的響應(yīng)者則有事件的監(jiān)聽器,針對事件進(jìn)行監(jiān)聽,當(dāng)有此類事件傳遞至此事件響應(yīng)者就使用事件處理器來相應(yīng)事件并決定此事件是否繼續(xù)傳遞。比如像上一個(gè)程序中的,點(diǎn)擊“點(diǎn)我”以后事件就開始激發(fā)了,然后事件就會在控件樹上進(jìn)行傳遞,事件的響應(yīng)者安裝了監(jiān)聽器,當(dāng)監(jiān)聽到這個(gè)事件進(jìn)行響應(yīng),并決定這個(gè)事件是否繼續(xù)傳遞。
了解了路由事件后,這節(jié)來學(xué)習(xí)一下如何自定義路由事件。
【分析代碼】
在演示代碼前,我們不妨先看一段Button按鈕的Click路由事件源碼,從源碼中學(xué)習(xí)一下如何定義路由事件。
在ButtonBase中,跟Click路由事件相關(guān)的有如下四處代碼:
代碼一
代碼二
代碼三
代碼四
第一段是聲明了ClickEvent這一路由事件對象,這個(gè)不用多說;
第二段是聲明了ClickEvent路由事件對象的包裝器,它類似于屬性的get,set,方便我們從外部把路由事件的處理器附加到路由事件上。當(dāng)外部進(jìn)行“+=”操作時(shí),內(nèi)部就會執(zhí)行add塊,將事件處理附加到Click路由事件上,反之執(zhí)行“-=”操作時(shí),會執(zhí)行remove塊中的內(nèi)容;
第三段是構(gòu)造方法中構(gòu)建Click路由事件對象,跟創(chuàng)建依賴對象類似的是,路由事件對象的創(chuàng)建也不是直接new,而是通過EventManager類的RegisterRoutedEvent方法進(jìn)行注冊,該方法第一個(gè)參數(shù)是路由事件的名稱,微軟約定路由事件名稱要跟路由事件對象的包裝器名稱一致,并且跟路由事件對象去掉Event后綴的字樣也要一致。第二個(gè)參數(shù)是指路由事件的策略,也就是事件傳播的形式,有如下三種枚舉:
- RoutingStrategy.Tunnel:隧道式,是指事件從最外層的控件開始路由,直到路由到控件自己,就像一條自上往下的隧道,從window控件一路通到當(dāng)前觸發(fā)事件的控件;
- RoutingStrategy.Bubble:冒泡式,這個(gè)跟隧道式相反,它是從觸發(fā)事件的控件向上傳播,直到最上層停止;
- RoutingStrategy.Direct:直通式,跟原始事件模型一樣,不路由,直達(dá)事件處理器。
第三個(gè)參數(shù)是指定該路由事件的事件處理器是什么類型,第四個(gè)參數(shù)是指定該路由事件對象的宿主類型,第四個(gè)參數(shù)跟第一個(gè)參數(shù)共同用于路由事件對象的內(nèi)部創(chuàng)建使用:構(gòu)建hash code,確定路由事件對象唯一性,同依賴屬性一致,在一個(gè)類中不能注冊兩個(gè)同名的路由事件對象。
第四段是激發(fā)Click路由事件的方法,事件參數(shù)就是在此方法中處理,它是路由事件傳播之源。
【自定義路由事件】
下面我們就來根據(jù)以上語法,基于ButtonBase創(chuàng)建自己的Click路由事件:
public class MyRoutedEventArgs : RoutedEventArgs { public MyRoutedEventArgs(RoutedEvent routedEvent, object source) : base(routedEvent, source) { } public string RoutedMessage { get; set; } } public class MyButton : ButtonBase { public static readonly RoutedEvent MessageEvent = EventManager.RegisterRoutedEvent("Message", RoutingStrategy.Bubble, typeof(EventHandler<MyRoutedEventArgs>), typeof(MyButton)); public event RoutedEventHandler Message { add { this.AddHandler(MessageEvent, value); } remove { this.RemoveHandler(MessageEvent, value); } } protected override void OnClick() { base.OnClick(); MyRoutedEventArgs eventArgs = new MyRoutedEventArgs(MessageEvent, this) { RoutedMessage = "自定義路由事件被觸發(fā)了" }; this.RaiseEvent(eventArgs); } }
上述代碼中,我創(chuàng)建了一個(gè)MyButton,聲明了一個(gè)MessageEvent路由事件對象,值得注意的是,RegisterRoutedEvent的第三個(gè)參數(shù)我用的是:
typeof(EventHandler<MyRoutedEventArgs>)
而非:
typeof(RoutedEventHandler)
因?yàn)镽outedEventHandler的參數(shù)跟我自定義的事件參數(shù)不一致,需要使用EventHandler的泛型版指定我的事件參數(shù)類型,下面是RoutedEventHandler的聲明:
該參數(shù)類型是RoutedEventArgs,而我使用的是自定義的MyRoutedEventArgs類型。
XAML部分及事件處理器的代碼為:
在外層Grid上設(shè)置MyButton的Message事件監(jiān)聽及處理器。
運(yùn)行效果如下:
點(diǎn)擊“你好”,彈出MessageBox提示“自定義路由事件被觸發(fā)了”。
總結(jié)
到此這篇關(guān)于WPF自定義路由事件的文章就介紹到這了,更多相關(guān)WPF自定義路由事件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
ListView Adapter優(yōu)化 實(shí)例
ListView Adapter優(yōu)化 實(shí)例,需要的朋友可以參考一下2013-04-04C#利用反射來判斷對象是否包含某個(gè)屬性的實(shí)現(xiàn)方法
這篇文章主要介紹了C#利用反射來判斷對象是否包含某個(gè)屬性的實(shí)現(xiàn)方法,很有借鑒價(jià)值的一個(gè)技巧,需要的朋友可以參考下2014-08-08C#?wpf實(shí)現(xiàn)截屏框熱鍵截屏的示例代碼
這篇文章主要為大家詳細(xì)介紹了C#?wpf實(shí)現(xiàn)截屏框熱鍵截屏的相關(guān)知識,文中的示例代碼講解詳細(xì),具有一定的借鑒價(jià)值,有需要的小伙伴可以學(xué)習(xí)一下2023-09-09c#實(shí)現(xiàn)幾種數(shù)據(jù)庫的大數(shù)據(jù)批量插入
這篇文章主要介紹了c#實(shí)現(xiàn)幾種數(shù)據(jù)庫的大數(shù)據(jù)批量插入,主要包括SqlServer、Oracle、SQLite和MySQL,有興趣的可以了解一下。2017-01-01C#調(diào)用windows api關(guān)機(jī)(關(guān)機(jī)api)示例代碼分享
本文主要介紹了C#調(diào)用windows api關(guān)機(jī)的示例代碼,大家參考使用吧2014-01-01