溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C#如何對消息進(jìn)行封裝

發(fā)布時間:2021-12-01 14:01:40 來源:億速云 閱讀:159 作者:小新 欄目:編程語言

這篇文章給大家分享的是有關(guān)C#如何對消息進(jìn)行封裝的內(nèi)容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

一、C#消息概述

Windows下應(yīng)用程序的執(zhí)行是通過消息驅(qū)動的。消息是整個應(yīng)用程序的工作引擎,我們需要理解掌握我們使用的編程語言是如何封裝消息的原理。

1 什么是消息(Message)

消息就是通知和命令。在.NET框架類庫中的System.Windows.Forms命名空間中微軟采用面對對象的方式重新定義了Message。新的消息(Message)結(jié)構(gòu)的公共部分屬性基本與早期的一樣,不過它是面對對象的。

公共屬性:

HWnd    獲取或設(shè)定消息的處理函數(shù)

Msg     獲取或設(shè)定消息的ID號

Lparam  指定消息的LParam字段

Wparam  指定消息的WParam字段

Result  指定為響應(yīng)消息處理函數(shù)而向OS系統(tǒng)返回的值

2 消息驅(qū)動的過程

所有的外部事件,如鍵盤輸入、鼠標(biāo)移動、按動鼠標(biāo)都由OS系統(tǒng)轉(zhuǎn)換成相應(yīng)的消息發(fā)送到應(yīng)用程序的消息隊列。每個應(yīng)用程序都有一段相應(yīng)的程序代碼來檢索、分發(fā)這些消息到對應(yīng)的窗體,然后由窗體的處理函數(shù)來處理。

二、C#消息的封裝

C#對消息重新進(jìn)行了面對對象的封裝,在C#中消息被封裝成了事件。

System.Windows.Forms.Application類具有用于啟動和停止應(yīng)用程序和線程以及處理Windows消息的方法。

調(diào)用Run以啟動當(dāng)前線程上的應(yīng)用程序消息循環(huán),并可以選擇使其窗體可見。

調(diào)用Exit或ExitThread來停止消息循環(huán)。

C#中用Application類來處理消息的接收和發(fā)送的。消息的循環(huán)是由它負(fù)責(zé)的。

從本質(zhì)上來講,每個窗體一般都對應(yīng)一個窗體過程處理函數(shù)。那么,C#的一個Form實例(相當(dāng)于一個窗體)收到消息后是如何處理消息的?其實,這個問題的分析也就是展示了C#的消息封裝原理。

實現(xiàn)鼠標(biāo)左鍵按下的消息的響應(yīng)(WM_LBUTTONDOWN) 

this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseDown1);    this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseDown2);     private void Form1_MouseDown1(object sender, System.Windows.Forms.MouseEventArgs e)    {        if(e.Button==System.Windows.Forms.MouseButtons.Left)      System.Windows.Forms.MessageBox.Show("消息被Form1_MouseDown1函數(shù)響應(yīng)");    }     private void Form1_MouseDown2(object sender, System.Windows.Forms.MouseEventArgs e)    {     if(e.Button==System.Windows.Forms.MouseButtons.Left)      System.Windows.Forms.MessageBox.Show("消息被Form1_MouseDown2函數(shù)響應(yīng)");    }

上面this.MouseDown是C#中的一個事件。它的定義如下:

public event MouseEventHandler MouseDown;

而MouseEventHandler的定義為:

public delegate void MouseEventHandler( object sender,MouseEventArgs e);

實際上,上面定義了一個委托類型MouseEventHandler。委托了啟用了其它編程語言中的函數(shù)指針的解決方案。與C++的函數(shù)指針不同,委托是完全面向?qū)ο蟮?,同時封裝了對象實例和方法。本質(zhì)上,委托把一個實例和該實例上的方法函數(shù)封裝成一個可調(diào)用的實體,它是面對對象的、安全的。

我們可以把

this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseDown1);

這條語句看成向this.MouseDown添加一個函數(shù)指針。

事件是對象發(fā)送的消息,以發(fā)送信號通知操作的發(fā)生。引發(fā)(觸發(fā))事件的對象叫做事件發(fā)送方。捕獲事件并對事件作出響應(yīng)的對象叫做事件接收方。在事件通訊中,事件發(fā)送方類并不知道哪個對象或方法將接收到(處理)它引發(fā)的事件。所需要的是在發(fā)送方和接收方之間存在一個媒介(類似指針的機(jī)制)。.NET框架定義了一個特殊的類型(Delegate委托),該類型提供函數(shù)指針的功能。這樣,委托就等效于一個類型安全的函數(shù)指針或一個回調(diào)函數(shù)。

前面我們向this.MouseDown事件添加了兩個委托。

this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseDown1);   this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseDown2);

結(jié)果,我們的兩個函數(shù)Form1_MouseDown1、Form1_MouseDown2在我們單擊鼠標(biāo)左鍵的時候都會被調(diào)用,而且調(diào)用的順序和我們添加委托的順序一致。

WM_LBUTTONDOWN消息首先被Application類從應(yīng)用程序消息隊列中取出,然后分發(fā)到相應(yīng)的窗體。窗體使用MouseDown事件中的函數(shù)指針調(diào)用已經(jīng)添加的響應(yīng)函數(shù)。所以C#中的事件字段實質(zhì)上是一個函數(shù)指針列表,用來維護(hù)一些消息到達(dá)時的響應(yīng)函數(shù)的地址。    

三、結(jié)論

C#消息的工作流程:

C#消息被Application類從應(yīng)用程序消息隊列中取出,然后分發(fā)到消息對應(yīng)的窗體,窗體對象的***個響應(yīng)函數(shù)是對象中的protected override void WndProc(ref System.Windows.Forms.Message e)方法。

它再根據(jù)消息的類型調(diào)用默認(rèn)的消息響應(yīng)函數(shù)(如OnMouseDown),默認(rèn)的響應(yīng)函數(shù)然后根據(jù)對象的事件字段(如this.MouseDown )中的函數(shù)指針列表,調(diào)用用戶所加入的響應(yīng)函數(shù)(如Form1_MouseDown1和Form1_MouseDown2),而且調(diào)用順序和用戶添加順序一致。

四、再回首Application類

Application類有一個AddMessageFilter的靜態(tài)方法,通過它我們可以添加消息篩選器,以便在向目標(biāo)傳遞Windows消息時,檢視這些消息。

使用消息篩選器來防止引發(fā)特定事件,或在將某事件傳遞給事件處理程序之前使用消息篩選器對其執(zhí)行特殊操作。我們必須提供IMessageFilter接口的一個實現(xiàn),然后才可以使用消息篩選器。以下的示范代碼將演示在消息發(fā)往窗體前我們?nèi)绾螖r截它。我們攔截的同樣是WM_LBUTTONDOWN消息。

using System;   using System.Drawing;   using System.Collections;   using System.ComponentModel;   using System.Windows.Forms;   using System.Data;    namespace MessageMech4   {       //實現(xiàn)消息過濾器接口      public class CLButtonDownFilter : IMessageFilter      {         public bool PreFilterMessage(ref Message m)         {            if (m.Msg==0x0201)// WM_LBUTTONDOWN            {               System.Windows.Forms.MessageBox.Show("App中鼠標(biāo)左鍵按下");               //返回值為true, 表示消息已被處理,不要再往后傳遞,因此消息被截獲               //返回值為false,表示消息未被處理,需要再往后傳遞,因此消息未被截獲               return true;            }            return false;         }      }        /// < summary>      /// Summary description for WinForm.      /// < /summary>      public class WinForm : System.Windows.Forms.Form      {         /// < summary>         /// Required designer variable.         /// < /summary>         private System.Windows.Forms.Label label1;         private System.ComponentModel.Container components = null;          public WinForm()         {            //            // Required for Windows Form Designer support            //            InitializeComponent();             //            // TODO: Add any constructor code after InitializeComponent call            //            //安裝自己的過濾器            CLButtonDownFilter MyFilter=new CLButtonDownFilter();            System.Windows.Forms.Application.AddMessageFilter(MyFilter);         }          /// < summary>         /// Clean up any resources being used.         /// < /summary>         protected override void Dispose (bool disposing)         {            if (disposing)            {               if (components != null)               {                  components.Dispose();               }            }            base.Dispose(disposing);         }          #region Windows Form Designer generated code         /// < summary>         /// Required method for Designer support - do not modify         /// the contents of this method with the code editor.         /// < /summary>         private void InitializeComponent()         {            this.label1 = new System.Windows.Forms.Label();            this.SuspendLayout();            //             // label1            //             this.label1.BackColor = System.Drawing.Color.Transparent;            this.label1.Dock = System.Windows.Forms.DockStyle.Top;            this.label1.ForeColor = System.Drawing.Color.DarkViolet;            this.label1.Name = "label1";            this.label1.Size = new System.Drawing.Size(440, 32);            this.label1.TabIndex = 0;            this.label1.Text = "演示如何在App對象中處理消息,請點鼠標(biāo)左鍵";            this.label1.TextAlign = System.Drawing.ContentAlignment.BottomCenter;            //             // Form1            //             this.AutoScaleBaseSize = new System.Drawing.Size(7, 22);            this.BackColor = System.Drawing.Color.WhiteSmoke;            this.ClientSize = new System.Drawing.Size(440, 273);            this.Controls.AddRange(new System.Windows.Forms.Control[] {this.label1});            this.Font = new System.Drawing.Font("華文行楷", 15F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((System.Byte)(134)));            this.Name = "WinForm";            this.Text = "WinForm";             //消息響應(yīng)函數(shù)的調(diào)用順序和添加委托的順序一致            //即:以下命令將先調(diào)用Form1_MouseDown1再調(diào)用Form1_MouseDown2             //通過委托添加自己的鼠標(biāo)按鍵消息響應(yīng)函數(shù)1            this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseDown1);            //通過委托添加自己的鼠標(biāo)按鍵消息響應(yīng)函數(shù)2            this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.Form1_MouseDown2);             this.ResumeLayout(false);         }         #endregion          /// < summary>         /// 應(yīng)用程序的主入口點。         /// < /summary>         [STAThread]         static void Main()          {            Application.Run(new WinForm()); //啟動當(dāng)前Form線程上的應(yīng)用程序消息循環(huán)         }          //要點1         // 通過C#提供的事件接口添加自己的鼠標(biāo)按鍵事件的響應(yīng)函數(shù)         //         private void Form1_MouseDown1(object sender, System.Windows.Forms.MouseEventArgs e)         {             if(e.Button==System.Windows.Forms.MouseButtons.Left)               System.Windows.Forms.MessageBox.Show("消息被Form1_MouseDown1函數(shù)響應(yīng)");          }         private void Form1_MouseDown2(object sender, System.Windows.Forms.MouseEventArgs e)         {            if(e.Button==System.Windows.Forms.MouseButtons.Left)               System.Windows.Forms.MessageBox.Show("消息被Form1_MouseDown2函數(shù)響應(yīng)");          }         //要點2         //通過覆蓋基類的事件引發(fā)函數(shù)攔截消息         //         protected override  void OnMouseDown( MouseEventArgs e)         {            if(e.Button==System.Windows.Forms.MouseButtons.Left)               System.Windows.Forms.MessageBox.Show("消息被OnMouseDown函數(shù)響應(yīng)");             //如果需要截獲消息,可將base.OnMouseDown(e);語句注釋掉            base.OnMouseDown(e);         }         //要點3         //通過覆蓋基類的窗體函數(shù)攔截消息         //         protected override void WndProc(ref System.Windows.Forms.Message e)         {            //如果需要截獲消息,            //if(e.Msg==0x0201)// WM_LBUTTONDOWN            //   System.Windows.Forms.MessageBox.Show("消息被WndProc函數(shù)響應(yīng)");            //else            //   base.WndProc(ref e);             //不需要截獲消息則為            if(e.Msg==0x0201)// WM_LBUTTONDOWN               System.Windows.Forms.MessageBox.Show("消息被WndProc函數(shù)響應(yīng)");            base.WndProc(ref e);         }       }   }

以上代碼我們首先用類CLButtonDownFilter實現(xiàn)了IMessageFilter接口,在WinForm初始化的時候我們安裝了消息篩選器。程序?qū)嶋H執(zhí)行的時候,在點擊鼠標(biāo)左鍵的時候,程序僅僅會彈出一個"App中鼠標(biāo)左鍵按下"的消息框。因為我們在消息發(fā)往窗體前攔截了它,所以窗體將接收不到WM_LBUTTONDOWN消息。

如果我們把  

    if (m.Msg==0x0201)// WM_LBUTTONDOWN   {      System.Windows.Forms.MessageBox.Show("App中鼠標(biāo)左鍵按下");      return true;   }

改成

    if (m.Msg==0x0201)// WM_LBUTTONDOWN   {      System.Windows.Forms.MessageBox.Show("App中鼠標(biāo)左鍵按下");      return false;   }

那么,我們在Application類處理消息后,消息將繼續(xù)發(fā)往窗體。窗體的函數(shù)將可以處理此消息。程序執(zhí)行效果是順序彈出5個消息框。

1:< < App中鼠標(biāo)左鍵按下>>

2:< < 消息被WndProc函數(shù)響應(yīng)>>

3:< < 消息被OnMouseDown函數(shù)響應(yīng)>>

4:< < 消息被Form1_MouseDown1函數(shù)響應(yīng)>>

5:< < 消息被Form1_MouseDown2函數(shù)響應(yīng)>>

主要有兩種方法過濾實現(xiàn)過濾

***種:

protected override void WndProc(ref Message m)   {   if (m.Msg == 0x0201)   return;   else   base.WndProc(ref m);   }

第二種

不重寫WndProc

//實現(xiàn)消息過濾器接口   public class CLButtonDownFilter : IMessageFilter   {   public bool PreFilterMessage(ref Message m)   {   if (m.Msg == 0x0201)// WM_LBUTTONDOWN   {   //返回值為true, 表示消息已被處理,不要再往后傳遞,因此消息被截獲   //返回值為false,表示消息未被處理,需要再往后傳遞,因此消息未被截獲   return true;   }   return false;   }   }

CLButtonDownFilter MyFilter = new CLButtonDownFilter();

System.Windows.Forms.Application.AddMessageFilter(MyFilter);

感謝各位的閱讀!關(guān)于“C#如何對消息進(jìn)行封裝”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI