c# 事件和EventManager

事件

基本用法

關(guān)鍵字event,聲明格式為:

public event <委托類型> <事件對象>

事件的處理方法:適用于該委托的方法

數(shù)據(jù)的觸發(fā):

  • 綁定同類事件,綁定時,可以綁定新的委托對象(更容易理解的寫法),也可以隱式轉(zhuǎn)換,直接綁定方法。
  • 手動觸發(fā)

例子:


    //新建一個EventArgs類的子類用于處理
    class MessageArrivedEventArgs : EventArgs
    {
        private string message;

        public string Message { get => message; }

        public MessageArrivedEventArgs()
        {
            message = "No message sent";
        }
        public MessageArrivedEventArgs(string newMessage)
        {
            message = newMessage;
        }
    }
    //事件的處理方法
    class Display
    {
        internal void DisplayMessage(object sender, MessageArrivedEventArgs e)
        {
            Console.WriteLine("Message arrived from:" + ((Connection)sender).Name);
            Console.WriteLine("Message text:" + e.Message);
        }
    }
    class Connection
    {
        //事件聲明
        //EventHandler是系統(tǒng)自建的用于處理事件的委托
        public event EventHandler<MessageArrivedEventArgs> MessageArrived;
        public String Name { get; set; }
        private Timer pollTimer;
        public static Random random = new Random();
        public Connection()
        {
            pollTimer = new Timer(100);
            //達(dá)到時間間隔時用CheckForMessage方法處理事件。(類型EvenHandler<MessageArrivedArgs>已經(jīng)隱式轉(zhuǎn)換)
            pollTimer.Elapsed += CheckForMessage;
        }

        public void Connect() => pollTimer.Start();
        public void Disconnect() => pollTimer.Stop();

        private void CheckForMessage(object sender, ElapsedEventArgs e)
        {
            Console.WriteLine("Checking for new messages.");
            if (random.Next(9) == 0)
            {
                //觸發(fā)事件。
                MessageArrived?.Invoke(this, new MessageArrivedEventArgs(DateTime.Now.ToLongTimeString()));
            }
        }
    }
    //主程序
    class MainControll
    {
        static void Main(string[] args)
        {
            Connection connection = new Connection();
            Connection connectionB = new Connection();
            connection.Name = "First connection";
            connectionB.Name = "Second connection";
            Display display = new Display();
            //事件觸發(fā)時用DisplayMessage方法處理事件
            connection.MessageArrived += display.DisplayMessage;
            connectionB.MessageArrived += display.DisplayMessage;
            connection.Connect();
            connectionB.Connect();
            System.Threading.Thread.Sleep(2000);
            ReadKey();
        }
    }

匿名委托方法

當(dāng)一個事件處理方法僅在一處調(diào)用時,可以干脆寫成匿名方法,比如,如果上述示例代碼中的DisplayMessage僅調(diào)用一次的話,可以寫成以下形式:

connection.MessageArrived += delegate(Conection sender,MessageArrivedEventArgs e)
{
    Console.WriteLine("Message arrived from:" + ((Connection)sender).Name);
    Console.WriteLine("Message text:" + e.Message);
}

寫成匿名方法,可以更加直觀。

EventHandler

分為默認(rèn)的EventHandler和帶有類型的EventHandler<T>,后者可以指定事件實(shí)參的類型。

EventManager

EventManager類在大型應(yīng)用開發(fā)中可以非常好用的來設(shè)置全局事件,起到類似切面編程的效果,比如,為一個已經(jīng)基本開發(fā)完畢的應(yīng)用添加權(quán)限控制功能,就可以用到。該類只有五個方法:

 public static class EventManager
    {
        //
        // 摘要:
        //     為已注冊到事件系統(tǒng)的路由事件返回標(biāo)識符。
        //
        // 返回結(jié)果:
        //     包含注冊對象的 System.Windows.RoutedEvent 類型的數(shù)組。
        public static RoutedEvent[] GetRoutedEvents();
        //
        // 摘要:
        //     查找使用所提供的所有者類型注冊的事件的所有路由事件標(biāo)識符。
        //
        // 參數(shù):
        //   ownerType:
        //     從其開始搜索的類型。搜索中包含基類。
        //
        // 返回結(jié)果:
        //     如果找到任何匹配項(xiàng),則返回匹配路由事件標(biāo)識符的數(shù)組;否則返回 null。
        public static RoutedEvent[] GetRoutedEventsForOwner(Type ownerType);
        //
        // 摘要:
        //     為特定路由事件注冊類處理程序。
        //
        // 參數(shù):
        //   classType:
        //     聲明類處理的類的類型。
        //
        //   routedEvent:
        //     要處理的事件的路由事件標(biāo)識符。
        //
        //   handler:
        //     對類處理程序?qū)崿F(xiàn)的引用。
        [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
        public static void RegisterClassHandler(Type classType, RoutedEvent routedEvent, Delegate handler);
        //
        // 摘要:
        //     使用處理事件數(shù)據(jù)已標(biāo)記為已處理的事件的選項(xiàng),為特定路由事件注冊類處理程序。
        //
        // 參數(shù):
        //   classType:
        //     聲明類處理的類的類型。
        //
        //   routedEvent:
        //     要處理的事件的路由事件標(biāo)識符。
        //
        //   handler:
        //     對類處理程序?qū)崿F(xiàn)的引用。
        //
        //   handledEventsToo:
        //     如果即使已將路由事件的參數(shù)標(biāo)記為已處理時也調(diào)用此類處理程序,則為 true;如果保留不對任何標(biāo)記為已處理的事件調(diào)用處理程序的默認(rèn)行為,則為 false。
        public static void RegisterClassHandler(Type classType, RoutedEvent routedEvent, Delegate handler, bool handledEventsToo);
        //
        // 摘要:
        //     向 Windows Presentation Foundation (WPF) 事件系統(tǒng)注冊新的路由事件。
        //
        // 參數(shù):
        //   name:
        //     路由事件的名稱。該名稱在所有者類型中必須是唯一的,并且不能為 null 或空字符串。
        //
        //   routingStrategy:
        //     作為枚舉值的事件的路由策略。
        //
        //   handlerType:
        //     事件處理程序的類型。該類型必須為委托類型,并且不能為 null。
        //
        //   ownerType:
        //     路由事件的所有者類類型。該類型不能為 null。
        //
        // 返回結(jié)果:
        //     新注冊的路由事件的標(biāo)識符。現(xiàn)在可將該標(biāo)識符對象存儲為類中的靜態(tài)字段,然后將其用作將處理程序附加到事件的方法的參數(shù)。路由事件標(biāo)識符也用于其他事件系統(tǒng) APIs。
        public static RoutedEvent RegisterRoutedEvent(string name, RoutingStrategy routingStrategy, Type handlerType, Type ownerType);
    }

官方文檔非常詳細(xì)了,可以看到,除了查詢由Manager管理的事件,主要形式功能的方法有兩個

  • RegisterClassHandler 最關(guān)鍵的方法之一,前三個參數(shù)為類型,路由事件,事件處理委托,最后一個可缺省參數(shù)決定是否處理已經(jīng)被處理過的路由事件。
  • RegisterRoutedEvent 向WPF中注冊自定義路由事件的方法。

對于RegisterClassHandler的有效使用,可以大大提高應(yīng)用的開發(fā)效率。就拿掃雷這款游戲而言,掃雷的界面上每一個各自都是Button,如果我們對每個Button的Click事件都進(jìn)行分別處理,是一件沒有必要的事情。而使用該方法,我們可以對所有Button控件來進(jìn)行處理。

下面舉一個全局處理權(quán)限的例子:

EventManager.RegisterClassHandler(typeof(TabControl), Selector.SelectionChangedEvent, new RoutedEventHandler(DisableTabControl));

針對全局的TabControl空間的SelectionChangedEvent去進(jìn)行處理,處理方法如下,如果是在C# 6環(huán)境下,還可以寫的再簡單點(diǎn)。

private void DisableTabControl(object sender, RoutedEventArgs e)
        {
            if (sender is TabControl)
            {
                var tabControl = sender as TabControl;
                foreach (var item in tabControl.Items)
                {
                    if (item is TabItem)
                    {
                        var tabItem = item as TabItem;
                        var valueGot = GlobalParams.FunctionDictionary.TryGetValue(tabItem.Header.ToString(), out string auth);
                        if (valueGot && !GlobalParams.AuthSet.Contains(auth))
                        {
                            tabItem.Visibility = Visibility.Hidden;
                            if (tabItem == tabControl.SelectedItem)
                            {
                                tabControl.SelectedItem = null;
                            }
                        }
                    }
                }
            }
        }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,628評論 19 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,156評論 25 708
  • 事件 事件含義 事件由對象引發(fā),通過我們提供的代碼來處理。一個事件我們必須訂閱(Subscribe)他們,訂閱一個...
    天堂邁舞閱讀 3,148評論 1 7
  • 一首詩(三十) 一分鐘很短 但過了這一分鐘 便是明天 一分鐘很短 但過了這一分鐘 便是明年 一分鐘很短 但過了這一...
    碎塵啊閱讀 205評論 0 0
  • 前臺代碼 懸浮事件
    三只倉鼠閱讀 1,082評論 0 0

友情鏈接更多精彩內(nèi)容