WPF學習之事件的學習(二)

来源:http://www.cnblogs.com/Melvin-Dong/archive/2016/08/07/5746694.html
-Advertisement-
Play Games

3.2自定義路由事件 為了方便程式中對象之間的通信,通常需要我們自己定義一些路由事件。那麼如何去創建自定義路由事件呢?下麵通過一個例子來說明自定義路由事件的創建。 創建自定義路由事件大體來說分為三個步驟: 首先,定義路由事件與依賴屬性的定義手法極為相似——申明一個由public static rea ...


  3.2自定義路由事件

  為了方便程式中對象之間的通信,通常需要我們自己定義一些路由事件。那麼如何去創建自定義路由事件呢?下麵通過一個例子來說明自定義路由事件的創建。

  創建自定義路由事件大體來說分為三個步驟:

  1. 聲明並註冊路由事件

    首先,定義路由事件與依賴屬性的定義手法極為相似——申明一個由public static readonly修飾的RoutedEvent類型的欄位,然後使用EventManager類的RegisterRoutedEvent方法進行註冊。 完整的註冊路由事件的代碼如下:

  1. //聲明並註冊路由事件
    public static readonly RoutedEvent ClickEvent = EventManger.RegisterRoutedEvent("Click",RoutingStrategy.Bubble,typeof(RoutedEventHandler),typeof(ButtonBase));

    我們來分析一下 EventManger.RegisterRoutedEvent這個方法的四個參數。

      第一個參數是string類型的,被稱為路由事件的名稱。按照微軟的建議,這個字元串RoutedEvent變數的首碼和CLR事件包裝器的名稱一致。再本例中,路由變數的名稱為ClickEvent,則此字元串為Click。

      第二個參數為路由事件的策略,在WPF中,路由事件總共有三種策略:

    • Bubble,冒泡式:路由事件從激發它的容器開始,一層層向上傳遞,直至最外層容器(Window或者Page)。
    • Tunnel,隧道式:路由事件的傳遞方向和Bubble正好相反,是由UI樹的樹根向激發事件的控制項移動
    • Direct,直達式:模仿CLR直接事件,將消息直接送達事件處理器

      第三個參數用於指定事件處理器的類型。事件處理器的返回值類型和參數列表必須與此參數指定的委托保持一致,不然會導致編譯時拋出異常。

      第四個參數用於指明路由事件的宿主是哪個類型的。

  2. 為路由事件創建CLR事件包裝

    為路由事件添加CLR事件包裝是為了把路由事件暴露的很像一個傳統的直接事件,如果不關註底層實現,程式員是不會感覺到它與傳統的直接事件的區別。編程中仍然可以使用+=號為事件添加事件處理器和使用-=為事件移除不再使用的事件處理器。

  3. 創建可以激發路由事件的方法

    激發路由事件的方法很簡單,首先創建一個需要事件攜帶的消息並把它與路由事件相關聯,然後調用元素的RaiseEvent方法將事件發送出去。

 

  下麵我們自己動手創建了一個路由事件,這個事件的用途是報告事件發生的時間。以此為例,說明自定義路由事件的創建方法。

  在上文中提到過,創建自定義路由事件有三個步驟,分別是聲明並註冊路由事件、為路由事件添加CLR的包裝、激發路由事件。在本例中,我們要激發路由事件,首先得創建一個需要事件攜帶的消息。正所謂“兵馬未動,糧草先行”,我們首先創建一個用於承載消息的事件參數。

  

 1 //用於承載時間消息的事件參數
 2     class ReportTimeEventArgs : RoutedEventArgs
 3     {
 4         public DateTime ClickTime { get; set; }
 5 
 6         public ReportTimeEventArgs(RoutedEvent routedEvrent,object source):base(routedEvrent,source)
 7         {
 8 
 9         }
10     }

  然後,在創建一個Button類的派生類並按前述步驟為其添加路由事件:

  

 1 class TimeButton : Button
 2     {
 3         //聲明、註冊路由事件
 4         public static readonly RoutedEvent ReportTimeEvent = EventManager.RegisterRoutedEvent("ReportTime", RoutingStrategy.Bubble, typeof(EventHandler<ReportTimeEventArgs>), typeof(TimeButton));
 5 
 6         //CLR事件包裝器
 7         public event RoutedEventHandler ReportTime
 8         {
 9             add { this.AddHandler(ReportTimeEvent, value); }
10             remove { this.RemoveHandler(ReportTimeEvent,value); }
11         }
12 
13         //激發路由事件,借用Click事件的激發方法
14 
15         protected override void OnClick()
16         {
17             base.OnClick();
18 
19             ReportTimeEventArgs args = new ReportTimeEventArgs(ReportTimeEvent, this);
20             args.ClickTime = DateTime.Now;
21             this.RaiseEvent(args);
22         }
23     }

  下麵是程式的界面XAML代碼:

  

 1 <Window x:Class="_02_自定義路由事件.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:local="clr-namespace:_02_自定義路由事件"
 7         mc:Ignorable="d"
 8         Title="Routed Event" Height="300" Width="300" Name="window_1"
 9         local:TimeButton.ReportTime="ReportTimeHandle">
10     <Grid Name="grid_1" local:TimeButton.ReportTime="ReportTimeHandle">
11         <Grid Name="grid_2" local:TimeButton.ReportTime="ReportTimeHandle">
12             <Grid Name="grid_3" local:TimeButton.ReportTime="ReportTimeHandle">
13                 <StackPanel Name="stackPanel_1" local:TimeButton.ReportTime="ReportTimeHandle">
14                     <ListBox Name="listBox" Margin="10"></ListBox>
15                     <local:TimeButton x:Name="timeButton" Width="80" Height="80"
16                                       Content="報時" local:TimeButton.ReportTime="ReportTimeHandle">                        
17                     </local:TimeButton>
18                 </StackPanel>
19             </Grid>
20         </Grid>
21     </Grid>
22 </Window>

  在UI界面上,以Window為根,套了三層Grid和一層StackPanel(在裡面都設置了Name屬性),在最內部的StackPanel裡面放置了一個ListBox和TimeButton(也就是上面剛剛創建的Button類的派生類)。我們可以看出,從最外層的Window到最內層的TimeButton,都在監聽者ReportTimeEvent 這個路由事件,並用ReportTimeHandle方法來響應這個事件。ReportTimeHandle的代碼如下:

  

 1 //ReportTimeEvent路由事件處理器
 2         private void ReportTimeHandle(object sender, ReportTimeEventArgs e)
 3         {
 4             FrameworkElement element = sender as FrameworkElement;
 5             string timeStr = e.ClickTime.ToLongTimeString();
 6             string content = string.Format("{0}到達{1}", timeStr, element.Name);
 7             this.listBox.Items.Add(content); 9        }

  運行程式,效果如下圖所示:

      

  在這個例子中我們採用的路由事件的策略為冒泡式(bubble),我們對程式做個簡單的修改,在聲明和註冊路由事件時,將其事件的策略改為隧道式(tunnel):

  

//聲明、註冊路由事件
        public static readonly RoutedEvent ReportTimeEvent = EventManager.RegisterRoutedEvent("ReportTime", RoutingStrategy.Tunnel, typeof(EventHandler<ReportTimeEventArgs>), typeof(TimeButton));

  效果如下圖所示:

  

  對比兩張效果圖,我們可以很清楚的看到,兩種不同的策略所帶來不同,藉此也能更好的理解之前所說的內容。

  這時候,大家有個疑問,如果讓一個路由事件在某個地方被處理之後不再向後傳呢?很簡單,在RoutedEventArgs類或者其派生類的實例中,其具有一個bool類型的屬性Handeled,一旦這個屬性被設置為true,那麼路由事件就不會再往下傳遞了。對應於我們這個例子,則需要做以下修改:

  

 1 //ReportTimeEvent路由事件處理器
 2         private void ReportTimeHandle(object sender, ReportTimeEventArgs e)
 3         {
 4             FrameworkElement element = sender as FrameworkElement;
 5             string timeStr = e.ClickTime.ToLongTimeString();
 6             string content = string.Format("{0}到達{1}", timeStr, element.Name);
 7             this.listBox.Items.Add(content);
 8 
 9             if (element == this.grid_2)
10             {
11                 e.Handled = true;
12             }
13         }

  這樣修改後的效果圖如下:

    

    To Be Continue!

 

 

 

  

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 聲明:本系列為原創,分享本人現用框架,未經本人同意,禁止轉載!http://yuangang.cnblogs.com 希望大家好好一步一步做,所有的技術和項目,都毫無保留的提供,希望大家能自己跟著做一套,還有,請大家放心,只要大家喜歡,有人需要,絕對不會爛尾,我會堅持寫完~ 如果你感覺文章有幫助,點 ...
  • 存儲過程:就像函數一樣的會保存在資料庫中--》可編程性 --》 存儲過程創建存儲過程:create proc JiaFa--需要的參數@a int,@b intas --存儲過程的內容 declare @c int; set @c = @a + @b; return @c;go public int ...
  • .NET Core中間件的註冊和管道的構建(2) 用UseMiddleware擴展方法註冊中間件類 0x00 為什麼要引入擴展方法 有的中間件功能比較簡單,有的則比較複雜,並且依賴其它組件。除了直接用ApplicationBuilder的Use()方法註冊中間件外,還可以使用ApplicationB ...
  • It has being ages to get back to cnblogs, Career path had been changed back to .Net development in 4 years ago....Things i just leart from my current ...
  • 什麼是Linq表達式?什麼是Lambda表達式? 如圖: 由此可見Linq表達式和Lamdba表達式並沒有什麼可比性。 那與Lamdba表達式相關的整條語句稱作什麼呢?在微軟並沒有給出官方的命名,在《深入理解C#》中稱為點標記。 ...
  • 背水一戰 Windows 10 之 控制項(文本類): TextBlock ...
  • 目錄索引 【無私分享:ASP.NET CORE 項目實戰】目錄索引 簡介 在程式設計中,我們很多情況下,會用到對文件的操作,在 上一個系列 中,我們有很多文件基本操作的示例,在Core中有一些改變,主要是我們常用的Server.MapPath()不存在了,不知道後續的版本會不會有,在這裡,我們只能自 ...
  • 前提: 自定義搜索且有分頁功能,比如搜索產品名的功能. 現象:當搜索充氣娃娃的時候返回100條記錄,翻到第五頁. 這時候搜索按摩棒,數據有200條,結果應該是第一頁的記錄,但是實際顯示的還是第五頁的結果. 也就是重新搜索後,pagenumber沒有變. 按網上大部分說的:重新設置option就行了 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...