C#語法——事件,逐漸邊緣化的大哥。

来源:https://www.cnblogs.com/kiba/archive/2018/08/13/9436431.html
-Advertisement-
Play Games

事件是C#的基礎之一,學好事件對於瞭解.NET框架大有好處。 事件最常見的比喻就是訂閱,即,如果你訂閱了我的博客,那麼,當我發佈新博客的時候,你就會得到通知。 而這個過程就是事件,或者說是事件運行的軌跡。 事件是發散,以我的博客為核心,向所有訂閱者發送消息。我們把這種發散稱之為[多播]。 最常見的事 ...


事件是C#的基礎之一,學好事件對於瞭解.NET框架大有好處。

事件最常見的比喻就是訂閱,即,如果你訂閱了我的博客,那麼,當我發佈新博客的時候,你就會得到通知。

而這個過程就是事件,或者說是事件運行的軌跡。

事件是發散,以我的博客為核心,向所有訂閱者發送消息。我們把這種發散稱之為[多播]。

最常見的事件用途是窗體編程,在Windows窗體應用程式和WPF應用程式中。

當在窗體中點擊按鈕,移動滑鼠等事件時,相應的後臺程式會收到通知,再執行代碼。

事件的定義

官方對事件的說明是這樣的:類或對象可以通過事件向其他類或對象通知發生的相關事情。

換成正常語言就是,事件可以定義成靜態的或普通的,所以事件就可以由聲明的對象調用,也可以直接通過類調用靜態事件。

事件是C#中的一種類型,除了框架為我們定義好的事件外,我們還可以自定義事件,用event關鍵字來聲明。

下麵我們來看最基礎的事件定義。

public delegate void TestDelegate(string message);                                                  
public event TestDelegate testEvent;

我們首先定義了一個委托,然後利用event關鍵字,定義一個事件。

整體上看,好像就是在定義一個委托,只是在委托的定義之前,加了個event關鍵字。

沒錯,事件的定義就是這樣,因為要聲明一個事件,需要兩個元素:

一,標識提供對事件的響應的方法的委托。

二,一個類,用存儲事件的數據。即,事件要定義在類中。

下麵我們來為這個事件賦值。

public void Init()
{   
    testEvent += new TestDelegate(EventSyntax_testEvent); 
    testEvent += EventSyntax_testEvent; 
}
private void EventSyntax_testEvent(string message)
{
    Console.WriteLine(message);
}

如代碼所示,我們使用了+=這個符號來為事件賦值,賦值的內容是一個委托和一個函數。

其中+=我們將他理解為【添加】。

代碼中,我們使用兩種賦值模式,但實際上都是為事件testEvent添加一個委。

第二種將函數直接【添加】到事件中,編譯時也會把函數轉換成委托【添加】到事件中。

系統提供事件

C#的框架都很經典,而每個經典框架都為我們提供了一些經典事件。

由於事件必須[標識響應方法的委托],所以這些事件所使用的委托都有一個共同的特點,命名中包含Event。

比如EventHandler,CancelEventHandler,RoutedEventHandler,ContextMenuEventHandler等。

其中最經典的就是EventHandler和RoutedEventHandler。

EventHandler:

EventHandler定義如下

[SerializableAttribute]
[ComVisibleAttribute(true)]
public delegate void EventHandler(
	object sender,
	EventArgs e
)

他包含了兩個參數,即當我們為事件添加EventHandler委托後,再去觸發該事件;被觸發的委托將得到object sender和EventArgs e兩個參數。

sender:代表源,即觸發該事件的控制項。

e:代表事件參數,即觸發該事件後,事件為被觸發的委托,傳遞了一些參數,以方便委托在處理數據時,更便捷。

根據這個原理,我們可以分析出很多東西。

比如,當控制項DataGrid的事件被觸發時,只要查看一下sender的真實類型,就可以知道,到底是DataGrid觸發的事件,還是DataGridRow或DataGridCell觸發的了。

RoutedEventHandler:

RoutedEventHandler即路由事件,他的定義如下

public delegate void RoutedEventHandler(
	Object sender,
	RoutedEventArgs e
)

RoutedEventHandler也為我們提供了sender和e兩個參數。

但RoutedEventHandler特別之處是,他的sender並不一定是真實的源,因為他是一個冒泡路由事件,即上升事件。

這裡如果大家有好奇心去看官方文檔,那麼會在相關的介紹中看到兩個單詞sender和source。

通過這兩個單詞,我們會清晰的瞭解路由事件。簡單描述一下sender和source,它們一個是發送者,一個是源。

在EventHandler中,sender即source,因為它是直接事件。而在冒泡事件中,sender不一定等於source。即發送者不一定是源。

下麵我們用WPF來看看路由事件。

我們首先在XAML頁面定義一個RadioButton按鈕,然後設置他的模板是Button。然後分別定義各自的Click方法。

Xaml頁面如下:

 <RadioButton Click="btnParent_Click">
            <RadioButton.Template>
                <ControlTemplate>
                    <StackPanel>
                        <TextBlock Text="我的名字" ></TextBlock>
                        <Button Content="Kiba518"   Click="btnClild_Click" ></Button>
                    </StackPanel>
                </ControlTemplate>
            </RadioButton.Template> 
</RadioButton> 

cs文件事件如下:

 private void btnParent_Click(object sender, RoutedEventArgs e)
 {
     string type = sender.GetType().ToString();//RadioButton
 }

 private void btnClild_Click(object sender, RoutedEventArgs e)
 {
     string type = sender.GetType().ToString();//Button
 }

運行起來,我們點擊按鈕,通過斷點我們可以看到,我們點擊的按鈕觸發了btnClild_Click和btnParent_Click事件

順序是先btnClild_Click後btnParent_Click。

通過獲取sender的類型,我也可以看到,btnClild_Click的sender類型是Button,而btnParent_Click的sernder類型是RadioButton。

事件驅動編程

事件驅動編程這個概念給我的感覺很怪,因為一直用C#,而C#的很多框架都是事件驅動的,所以一直覺得事件驅動是理所當然。

而當事件驅動設計這個詞經常出現後,反而感覺怪怪的。

就好像,天天吃大米飯,突然有一天,所有人都說大米飯好香的感覺一樣,你一聽就感覺怪怪的。

因為事件驅動對於C#開發而言,實在太普通了。當然,這也得益於微軟框架做的實在是太好了。

所以,我也不知道如何在C#里講事件驅動編程。因為使用C#的框架就是使用事件驅動編程。

事件和委托到底是什麼關係?

事件是用來多播的,並且用委托來為事件賦值,可以說,事件是基於委托來實現的。

但委托中也有多播,那為什麼要單獨弄出來一個事件呢?

首先,存在即合理,事件一定有他存在的意義。 

事件存在的意義

我對事件存在的意義是這樣理解的。我們在C#編寫框架時,幾乎不用委托的多播,因為委托的多播和事件存在嚴重的二義性。雖然編寫框架的人學會了使用委托的多播,但使用框架的同事可能並還不太熟練,而且C#框架中,大多是使用事件來進行多播的。

所以委托的多播和事件一起使用的框架,會造成使用這個框架的初級開發者很多困惑,而這種困惑,會產生很多不必要的問題。

比如, 你定義了一個委托,另一個開發者用這個委托做了個多播,當第三個開發者來維護這段代碼時,如果他是新手,不瞭解委托的多播,那就很有可能只修改了委托調用的代碼。而沒有去同步多播這個委托的代碼。那系統就產生了隱藏的bug。

那麼,事件和委托到底是什麼關係呢?

事件與委托的確存在千絲萬縷的關係,怎麼講都是正確的。但,C#開發者只需要記住,他們倆沒關係即可。在C#事件是事件,委托是委托。兩者就如同int和string一樣,沒有任何關係。

原因很簡單,學習的過程中儘量降低概念混淆。而且,在C#開發中,好的架構者也通常會將事件和委托分離,所以,就認為事件和委托沒有關係即可。

結語

其實事件很好理解,一點不複雜。我在寫這篇文章的過程中,也沒想到什麼特別的或者說比較高級的用法。

但真實的應用場景中,我的感覺是,隨著MVVM的成長,事件其實在被逐漸拋棄。雖然微軟做了很多經典的事件驅動框架。但那都是過去了。

比如WPF雖然支持事件驅動,但MVVM在WPF下的表現堪稱完美,所以WPF下的事件幾乎沒有人用了。

再比如前端的Angularjs等框架,提供了優質的MVVM使用效果,也讓新的前端設計師逐漸放棄了事件。

所以,事件在未來的編程中,很可能將不在有那麼重要的地位了。但學好事件,對於我們理解微軟框架,還是有很大幫助的。

C#語法——元組類型

C#語法——泛型的多種應用

C#語法——await與async的正確打開方式

C#語法——委托,架構的血液

我對C#的認知。

----------------------------------------------------------------------------------------------------

註:此文章為原創,歡迎轉載,請在文章頁面明顯位置給出此文鏈接!
若您覺得這篇文章還不錯,請點擊下右下角的推薦】,非常感謝!
如果您覺得這篇文章對您有所幫助,那就不妨支付寶小小打賞一下吧。 

 


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

-Advertisement-
Play Games
更多相關文章
  • 一、為什麼要用synchronized關鍵字 首先多線程中多個線程運行面臨共用數據同步的問題。 多線程正常使用共用數據時需要經過以下步驟: 1.線程A從共用數據區中複製出數據副本,然後處理。 2.線程A將處理好的數據副本寫入共用數據區。 3.線程B從共用數據區中複製出數據副本。 如此迴圈,直到線程結 ...
  • 最近維護一個項目,裡面用到ClientDataSet,由於之前接觸ClientDataSet比較少,所以這個星期補了一下關於ClientDataSet的知識,併在此記錄下我所瞭解到的並應用到實際項目中的ClientDataSet的知識。 項目新需求:1.從別的資料庫導入物料資料,並允許操作員做修改後 ...
  • 在最近的秋招中,阿裡和多益網路都問到了這個問題,雖然很簡單,但是我還是想總結一下,感興趣的可以看一下我的 "個人博客網站(Spring+MyBatis+redis+nginx+mysql)" (適合菜鳥),最近會抽空把最近面試遇到的問題總結一下。 本文針對問題:深克隆和淺克隆的區別和實現方式?(阿裡 ...
  • 1、數據結構 從不同的角度,可以分為邏輯結構和物理結構 邏輯結構:是數據元素之間的相互關係 集合結構 線性結構 樹形結構 圖形結構 物理結構:數據的邏輯結構在電腦的存儲形式 順序存儲結構:數據間的邏輯關係和物理關係一致 鏈式存儲結構 2、演算法時間複雜度 時間複雜度T(n)=O(f(n));f(n) ...
  • 由於需要在公司的內網進行神經網路建模試驗(https://www.cnblogs.com/NosenLiu/articles/9463886.html),為了更方便的在內網環境下快速的查閱資料,構建深度學習模型,我決定使用爬蟲來對深度學習框架keras的使用手冊進行爬取。 keras中文文檔的地址是 ...
  • 編程零基礎如何學習Python 如果你是零基礎,註意是零基礎,想入門編程的話,我推薦你學Python。雖然國內基本上是以C語言作為入門教學,但在麻省理工等國外大學都是以Python作為編程入門教學的。 那麼如何學習Python呢? 第一步:先把刀磨好 俗話說得好,磨刀不誤砍柴工,這個你不得不信,反正 ...
  • 在具備了volatile、CAS和模板方法設計模式的知識之後,我們可以來深入學習下AbstractQueuedSynchronizer(AQS),本文主要想從AQS的產生背景、設計和結構、源代碼實現及AQS應用這4個方面來學習下AQS,文章耗時一個月,所以篇幅有點長,需要一點耐心。 1、AQS產生背 ...
  • Size Balanced Tree 挺有意思的, 適合新手練習 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...