最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#開(kāi)發(fā)WPF程序中的弱事件模式

 更新時(shí)間:2022年06月20日 10:46:46   作者:天方  
這篇文章介紹了C#開(kāi)發(fā)WPF程序中的弱事件模式,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

在C#中,得益于強(qiáng)大的GC機(jī)制,使得我們開(kāi)發(fā)程序變得非常簡(jiǎn)單,很多時(shí)候我們只需要管使用,而并不需要關(guān)心什么時(shí)候釋放資源。但是,GC有的時(shí)并不是按照我們所期望的方式工作。

例如,我想實(shí)現(xiàn)一個(gè)在窗口的標(biāo)題欄中實(shí)時(shí)顯示當(dāng)前的時(shí)間,一個(gè)比較常規(guī)的做法如下:

var?timer =?new?DispatcherTimer() { Interval =?TimeSpan.FromSeconds(1) };
timer.Tick += (_s, _e) =>?this.Title =?DateTime.Now.ToString();
timer.Start();

這種做法看起來(lái)非常簡(jiǎn)單而直接,它也確實(shí)能老老實(shí)實(shí)按照我們所設(shè)計(jì)的那樣在窗口中實(shí)時(shí)顯示并更新時(shí)間。但是,有經(jīng)驗(yàn)的程序員們就知道,這里存在一個(gè)隱患:這個(gè)窗口永遠(yuǎn)不會(huì)釋放。比較簡(jiǎn)單的驗(yàn)證方式是:手動(dòng)關(guān)閉窗口,調(diào)用GC.Collect()函數(shù),發(fā)現(xiàn)析構(gòu)函數(shù)是不會(huì)調(diào)用的。

可能有的人會(huì)問(wèn)了:不是有萬(wàn)能的GC嘛,為什么這個(gè)窗口不會(huì)釋放?究其原因也非常簡(jiǎn)單,DispatchTimer的Tick事件中包含了對(duì)Window的引用,當(dāng)窗口關(guān)閉時(shí),DispatchTimer仍然在執(zhí)行,因此Window就得不到釋放。

知道了原因后,要解決也不難:在Window的關(guān)閉事件中,停止Timer的調(diào)用即可。這種方式確實(shí)行之有效,但顯得不大優(yōu)雅,感覺(jué)回到了要手動(dòng)控制申請(qǐng)和釋放的C語(yǔ)言年代,沒(méi)有了GC自動(dòng)管理下的"管殺不管埋"的便捷感覺(jué)。 那么,有沒(méi)有一種我們只管使用,而不管釋放的方案呢,答案就是弱事件模式。

在弱事件模式下,事件委托只保留對(duì)象的弱引用,這樣GC仍然能將該對(duì)象給回收掉。例如,對(duì)于上述代碼,可以修改如下:

var timer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(1) };
WeakEventManager<DispatcherTimer, EventArgs>.AddHandler(timer, "Tick", (_s, _e) => this.Title = DateTime.Now.ToString());
timer.Start();

由于Timer沒(méi)有保存Window的強(qiáng)引用,當(dāng)Windows關(guān)閉后,是會(huì)被GC回收掉的。

現(xiàn)在看起來(lái)沒(méi)有什么問(wèn)題了,不過(guò),敏感的程序員們會(huì)發(fā)現(xiàn),這里還存在一個(gè)隱患:DispatchTimer沒(méi)有釋放。雖然我們沒(méi)有保存Timer的引用,但為了避免其被GC回收,內(nèi)部仍然會(huì)維持其引用,必須顯式停止。這里我們?nèi)匀豢梢岳萌跏录J?,在感知到回調(diào)對(duì)象被釋放時(shí),手動(dòng)停止Timer。要實(shí)現(xiàn)這個(gè)方法,必須我們實(shí)現(xiàn)自己的弱事件管理器: 

    public class DispatcherTimerManager : WeakEventManager
    {
        public static void Create(TimeSpan interval, EventHandler<EventArgs> handler)
        {
            var dispatcherTimer = new DispatcherTimer() { Interval = interval };
            DispatcherTimerManager.AddHandler(dispatcherTimer, handler);
            dispatcherTimer.Start();
        }

        public static void AddHandler(DispatcherTimer source, EventHandler<EventArgs> handler)
        {
            current.ProtectedAddHandler(source, handler);
        }

        public static void RemoveHandler(DispatcherTimer source, EventHandler<EventArgs> handler)
        {
            current.ProtectedRemoveHandler(source, handler);
        }

        static DispatcherTimerManager current;
        static DispatcherTimerManager()
        {
            current = new DispatcherTimerManager();
            SetCurrentManager(typeof(DispatcherTimerManager), current);
        }

        protected override ListenerList NewListenerList()
        {
            return new ListenerList<EventArgs>();
        }

        protected override void StartListening(object source)
        {
            var timer = (DispatcherTimer)source;
            timer.Tick += OnSomeEvent;
        }

        protected override void StopListening(object source)
        {
            var timer = (DispatcherTimer)source;
            timer.Tick -= OnSomeEvent;
            timer.Stop();
        }

        void OnSomeEvent(object sender, EventArgs e)
        {
            DeliverEvent(sender, e);
        }
    }

代碼比較簡(jiǎn)單:當(dāng)感知到回調(diào)對(duì)象被釋放時(shí),會(huì)執(zhí)行StopListening函數(shù)我們只需要重寫(xiě)改函數(shù),加入停止Timer操作即可。同樣,我們也可以基于弱事件模式實(shí)現(xiàn)一個(gè)IObservable的自動(dòng)管理類(lèi):

    public static class ObservableDispatcher
    {
        public static void AddHandler<T>(IObservable<T> source, EventHandler<DataEventArgs<T>> handler)
        {
            if ( Application.Current.Dispatcher != Dispatcher.CurrentDispatcher)
                throw new InvalidOperationException("需要在主線程上調(diào)用");

            AnymousDispatcher<T>.AddHandler(source, handler);
        }

        public static void RemoveHandler<T>(IObservable<T> source, EventHandler<DataEventArgs<T>> handler)
        {
            AnymousDispatcher<T>.RemoveHandler(source, handler);
        }


        class AnymousDispatcher<T> : WeakEventManager
        {
            public static void AddHandler(IObservable<T> source, EventHandler<DataEventArgs<T>> handler)
            {
                var wrapper = new ObservableEventWrapper<T>(source);
                current.ProtectedAddHandler(wrapper, handler);
            }

            public static void RemoveHandler(IObservable<T> source, EventHandler<DataEventArgs<T>> handler)
            {
                var wrapper = new ObservableEventWrapper<T>(source);
                current.ProtectedRemoveHandler(wrapper, handler);
            }

            static AnymousDispatcher<T> current;
            static AnymousDispatcher()
            {
                current = new AnymousDispatcher<T>();
                SetCurrentManager(typeof(AnymousDispatcher<T>), current);
            }

            protected override ListenerList NewListenerList()
            {
                return new ListenerList<DataEventArgs<T>>();
            }

            protected override void StartListening(object source)
            {
                var wrapper = source as ObservableEventWrapper<T>;
                wrapper.OnData += wrapper_OnData;
            }

            void wrapper_OnData(object sender, DataEventArgs<T> e)
            {
                DeliverEvent(sender, e);
            }

            protected override void StopListening(object source)
            {
                var wrapper = source as ObservableEventWrapper<T>;
                wrapper.OnData -= wrapper_OnData;
                wrapper.Dispose();
            }
        }

        class ObservableEventWrapper<T> : IDisposable
        {
            IDisposable disposeHandler;
            public ObservableEventWrapper(IObservable<T> dataSource)
            {
                disposeHandler = dataSource.Subscribe(onData);
            }

            void onData(T data)
            {
                OnData(this, new DataEventArgs<T>(data));
            }

            public event EventHandler<DataEventArgs<T>> OnData;

            public void Dispose()
            {
                disposeHandler.Dispose();
            }
        }
    }

限制:

弱事件模式非常有用,但不知道為什么微軟將其限制在了WPF框架中了,從其實(shí)現(xiàn)上來(lái)看,應(yīng)該是在UI線程上調(diào)用,但在MSDN上也沒(méi)有找到其限制的說(shuō)明。我試過(guò)在非UI線程上調(diào)用它,也是弱事件,但是不能觸發(fā)StopListening函數(shù)。不知道這樣有沒(méi)有什么影響,但最好還是在UI線程上調(diào)用它。

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • C#中按指定質(zhì)量保存圖片的實(shí)例代碼

    C#中按指定質(zhì)量保存圖片的實(shí)例代碼

    這篇文章主要介紹了C#中按指定質(zhì)量保存圖片的實(shí)例代碼,有需要的朋友可以參考一下
    2013-12-12
  • C#獲取打印機(jī)列表方法介紹

    C#獲取打印機(jī)列表方法介紹

    這篇文章介紹了C#獲取打印機(jī)列表的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • C#實(shí)現(xiàn)自定義單選和復(fù)選按鈕樣式

    C#實(shí)現(xiàn)自定義單選和復(fù)選按鈕樣式

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)定義單選和復(fù)選按鈕樣式,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • 基于C#調(diào)用c++Dll結(jié)構(gòu)體數(shù)組指針的問(wèn)題詳解

    基于C#調(diào)用c++Dll結(jié)構(gòu)體數(shù)組指針的問(wèn)題詳解

    下面小編就為大家分享一篇基于C#調(diào)用c++Dll結(jié)構(gòu)體數(shù)組指針的問(wèn)題詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2017-12-12
  • C#中async/await之線程上下文工作原理

    C#中async/await之線程上下文工作原理

    這篇文章主要為大家介紹了C#中async/await之線程上下文工作原理解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>
    2023-05-05
  • C#執(zhí)行表達(dá)式樹(shù)(Expression Tree)的具體使用

    C#執(zhí)行表達(dá)式樹(shù)(Expression Tree)的具體使用

    本文將深入探討表達(dá)式樹(shù)的基本概念、創(chuàng)建方法、修改和刪除節(jié)點(diǎn)、查詢和遍歷技巧以及在C#中的應(yīng)用示例,具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-03-03
  • C#操作XML方法詳解

    C#操作XML方法詳解

    對(duì)于XML讀寫(xiě)操作,項(xiàng)目中經(jīng)常要用到,之前木有好好總結(jié)過(guò),例如LINQ TO XML也用過(guò),這篇文章主要介紹了C#操作XML的方法
    2021-11-11
  • C#實(shí)現(xiàn)窗口之間的傳值

    C#實(shí)現(xiàn)窗口之間的傳值

    本文給大家介紹的是C#中利用靜態(tài)類(lèi)和靜態(tài)變量來(lái)實(shí)現(xiàn)窗口間傳值的方法和示例,非常的實(shí)用,有需要的小伙伴可以參考下。
    2015-06-06
  • C#獲取字符串后幾位數(shù)的方法

    C#獲取字符串后幾位數(shù)的方法

    這篇文章主要介紹了C#獲取字符串后幾位數(shù)的方法,實(shí)例分析了C#操作字符串的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-03-03
  • C# 反射(Reflection)的用處分析

    C# 反射(Reflection)的用處分析

    反射(Reflection)是C#里很重要的一個(gè)特性,其它語(yǔ)言也有這個(gè)特性,比如JAVA。反射這個(gè)特性是很實(shí)用的,如果使用過(guò)struts, hibernate, spring等等這些框架的話,便會(huì)知道反射這個(gè)特性是多么的強(qiáng)大了。在我接觸過(guò)的那些框架中,沒(méi)有一個(gè)框架是不使用反射的。
    2015-03-03

最新評(píng)論

绥化市| 长葛市| 丰台区| 阿城市| 竹溪县| 乌海市| 定结县| 莱西市| 乌审旗| 来凤县| 安龙县| 深水埗区| 洛浦县| 望江县| 平江县| 雅江县| 宾川县| 天津市| 灵寿县| 商都县| 航空| 汪清县| 四平市| 历史| 盐津县| 蕲春县| 界首市| 莫力| 山东| 小金县| 禹城市| 临猗县| 宜城市| 沁源县| 洛扎县| 荣昌县| 襄汾县| 郴州市| 隆化县| 晋江市| 长寿区|