Zayıf Olay Desenleri

Uygulamalarda, olay kaynaklarına eklenmiş olan işleyiciler, işleyiciyi kaynağa bağlayan dinleyici nesnesiyle birlikte yok edilmez. Bu durum bellek sızıntılarına neden olabilir. Windows Presentation Foundation (WPF) , belirli olaylar için adanmış bir yönetici sınıfı sağlayarak ve bu olay için dinleyicilerine bir arabirim uygulayarak bu sorunu gidermek için kullanılabilecek bir tasarım kalıbı sunar. Bu tasarım deseninin zayıf olay deseninin olduğu bilinmektedir.

Neden zayıf olay deseninin uygulanması?

Olayları dinlemek bellek sızıntılarına neden olabilir. Bir olayı dinlemek için tipik bir yöntem, bir kaynak üzerindeki olaya bir işleyici ekleyen dile özgü söz dizimini kullanmaktır. Örneğin, C# ' de söz dizimi şöyledir: source.SomeEvent += new SomeEventHandler(MyEventHandler) .

Bu teknik, olay kaynağından olay dinleyicisine güçlü bir başvuru oluşturur. Genellikle, bir dinleyici için bir olay işleyicisi iliştirmek, dinleyicinin, kaynağın nesne ömrü tarafından etkilenen bir nesne yaşam süresine sahip olmasına neden olur (olay işleyicisi açıkça kaldırılmadığı takdirde). Ancak belirli durumlarda, dinleyicinin nesne yaşam süresinin, uygulamanın yaşam süresine göre değil, uygulamanın görsel ağacına ait olup olmadığı gibi diğer faktörlere göre denetlenmesini isteyebilirsiniz. Kaynak nesne ömrü, dinleyicinin nesne ömrünü aşacak şekilde genişlediğinde, normal olay deseninin bir bellek sızıntısına yol açar: dinleyici, amaçlarından daha uzun bir süre etkin tutulur.

Zayıf olay deseninin bu bellek sızıntısı sorununu çözmek için tasarlanmıştır. Zayıf olay alanı, bir dinleyicinin bir olaya kaydolması gerektiğinde kullanılabilir, ancak dinleyici ne zaman kaydı kaldırılacak. Zayıf olay deseninin, kaynağın nesne ömrü, dinleyicinin yararlı nesne ömrünü aştığında de kullanılabilir. (Bu durumda, yararlı olarak sizin tarafınızdan belirlenir.) Zayıf olay deseninin, dinleyicinin herhangi bir şekilde nesne ömrü özelliklerini etkilemeden olay için kaydolmasına ve bu olayı almasına izin verir. Aslında, kaynaktan kapsanan başvuru, dinleyicinin çöp toplama için uygun olup olmadığını belirleyemez. Başvuru zayıf bir başvurudur, bu nedenle zayıf olay deseninin ve ilgili API 'lerin adlandırılması. Dinleyici atık olarak toplanamaz veya başka bir şekilde yok edilebilir ve kaynak olmayan işleyici başvurularını artık yok edilmiş bir nesneye korumadan devam edebilir.

Who Zayıf olay deseninin uygulanması gerekiyor mu?

Zayıf olay deseninin uygulanması, birincil olarak denetim yazarları için ilginç bir olaydır. Denetim yazarı olarak, denetiminizin davranışından ve kapsamasından büyük ölçüde sorumlu olursunuz ve onun eklendiği uygulamalarla ilgili etkileri vardır. Bu, özellikle açıklanan bellek sızıntısı sorununu işlemede denetim nesnesi ömrü davranışını içerir.

Belirli senaryolar doğal olarak zayıf olay deseninin uygulamasına ödünç vermez. Bu tür bir senaryo, veri bağlamadır. Veri bağlamada, kaynak nesnenin bağlama hedefi olan dinleyici nesnesinden tamamen bağımsız olması yaygındır. Veri bağlamasının birçok yönü, WPF olayların nasıl uygulandığı konusunda zayıf olay deseninin zaten uygulanmış olması.

Zayıf olay deseninin nasıl uygulanacağı

Zayıf olay deseninin uygulanması için üç yol vardır. Aşağıdaki tabloda üç yaklaşım listelenmekte ve her birini ne zaman kullanmanız gerektiği hakkında bazı rehberlik sunulmaktadır.

Yaklaşım Ne zaman uygulanacağı
Varolan zayıf bir olay Yöneticisi sınıfını kullan Abone olmak istediğiniz olaya karşılık gelen varsa WeakEventManager , var olan zayıf olay yöneticisini kullanın. WPF 'e dahil olan zayıf olay yöneticilerinin bir listesi için, sınıfındaki devralma hiyerarşisine bakın WeakEventManager . Dahil edilen zayıf olay yöneticileri sınırlı olduğundan, muhtemelen diğer yaklaşımlardan birini seçmeniz gerekir.
Genel bir zayıf olay Yöneticisi sınıfı kullanın Mevcut olmadığında genel WeakEventManager<TEventSource,TEventArgs> ' i kullanın WeakEventManager , uygulanması kolay bir yol istersiniz ve verimlilik konusunda endişe etmeniz gerekmez. Genel, WeakEventManager<TEventSource,TEventArgs> mevcut veya özel zayıf bir olay yöneticisinden daha az verimlidir. Örneğin, genel sınıf, olayın adı verilen olayı bulmaya yönelik daha fazla yansıma yapar. Ayrıca, genel kullanılarak olayı kaydeden kod, WeakEventManager<TEventSource,TEventArgs> var olan veya özel kullanmaktan daha ayrıntılıdır WeakEventManager .
Özel bir zayıf olay Yöneticisi sınıfı oluşturma WeakEventManagerMevcut olmadığında WeakEventManager ve en iyi verimliliği istediğinizde bir özel oluşturun. WeakEventManagerBir olaya abone olmak için özel kullanmak daha verimli olacaktır, ancak başlangıçta daha fazla kod yazma maliyetine tabi olursunuz.
Üçüncü taraf zayıf bir olay Yöneticisi kullanma NuGet, çok sayıda zayıf olay yöneticisi ve birçok WPF çerçevesi de modelini destekler (örneğin, bkz. esnek bir şekilde bağlanmış olay aboneliği için prronizin belgeleri).

Aşağıdaki bölümlerde, zayıf olay deseninin nasıl uygulanacağı açıklanır. Bu tartışmanın amaçları doğrultusunda Abone olunacak olay aşağıdaki özelliklere sahiptir.

  • Olay adı SomeEvent .

  • Olay, sınıfı tarafından tetiklenir EventSource .

  • Olay işleyicisinin türü: SomeEventEventHandler (veya EventHandler<SomeEventEventArgs> ).

  • Olay, olay işleyicilere türünde bir parametre geçirir SomeEventEventArgs .

Var olan zayıf bir olay Yöneticisi sınıfını kullanma

  1. Var olan zayıf bir olay Yöneticisi bulun.

    WPF 'e dahil olan zayıf olay yöneticilerinin bir listesi için, sınıfındaki devralma hiyerarşisine bakın WeakEventManager .

  2. Normal olay kancası yerine yeni zayıf olay yöneticisini kullanın.

    Örneğin, kodunuz bir olaya abone olmak için aşağıdaki kalıbı kullanıyorsa:

    source.SomeEvent += new SomeEventEventHandler(OnSomeEvent);  
    

    Aşağıdaki düzene göre değiştirin:

    SomeEventWeakEventManager.AddHandler(source, OnSomeEvent);  
    

    Benzer şekilde, kodunuz bir olaydan aboneliği kaldırmak için aşağıdaki kalıbı kullanıyorsa:

    source.SomeEvent -= new SomeEventEventHandler(OnSomeEvent);  
    

    Aşağıdaki düzene göre değiştirin:

    SomeEventWeakEventManager.RemoveHandler(source, OnSomeEvent);  
    

Genel zayıf olay Yöneticisi sınıfını kullanma

  1. WeakEventManager<TEventSource,TEventArgs>Normal olay kancası yerine genel sınıfı kullanın.

    WeakEventManager<TEventSource,TEventArgs>Olay dinleyicilerini kaydetmek için kullandığınızda, aşağıdaki kodda gösterildiği gibi, olay kaynağını ve türü EventArgs sınıf için tür parametreleri olarak girin ve çağırın AddHandler :

    WeakEventManager<EventSource, SomeEventEventArgs>.AddHandler(source, "SomeEvent", source_SomeEvent);  
    

Özel bir zayıf olay Yöneticisi sınıfı oluşturma

  1. Aşağıdaki sınıf şablonunu projenize kopyalayın.

    Bu sınıf WeakEventManager sınıfından devralır.

    class SomeEventWeakEventManager : WeakEventManager
    {
    
        private SomeEventWeakEventManager()
        {
        }
    
        /// <summary>
        /// Add a handler for the given source's event.
        /// </summary>
        public static void AddHandler(EventSource source,
                                      EventHandler<SomeEventEventArgs> handler)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (handler == null)
                throw new ArgumentNullException("handler");
    
            CurrentManager.ProtectedAddHandler(source, handler);
        }
    
        /// <summary>
        /// Remove a handler for the given source's event.
        /// </summary>
        public static void RemoveHandler(EventSource source,
                                         EventHandler<SomeEventEventArgs> handler)
        {
            if (source == null)
                throw new ArgumentNullException("source");
            if (handler == null)
                throw new ArgumentNullException("handler");
    
            CurrentManager.ProtectedRemoveHandler(source, handler);
        }
    
        /// <summary>
        /// Get the event manager for the current thread.
        /// </summary>
        private static SomeEventWeakEventManager CurrentManager
        {
            get
            {
                Type managerType = typeof(SomeEventWeakEventManager);
                SomeEventWeakEventManager manager =
                    (SomeEventWeakEventManager)GetCurrentManager(managerType);
    
                // at first use, create and register a new manager
                if (manager == null)
                {
                    manager = new SomeEventWeakEventManager();
                    SetCurrentManager(managerType, manager);
                }
    
                return manager;
            }
        }
    
        /// <summary>
        /// Return a new list to hold listeners to the event.
        /// </summary>
        protected override ListenerList NewListenerList()
        {
            return new ListenerList<SomeEventEventArgs>();
        }
    
        /// <summary>
        /// Listen to the given source for the event.
        /// </summary>
        protected override void StartListening(object source)
        {
            EventSource typedSource = (EventSource)source;
            typedSource.SomeEvent += new EventHandler<SomeEventEventArgs>(OnSomeEvent);
        }
    
        /// <summary>
        /// Stop listening to the given source for the event.
        /// </summary>
        protected override void StopListening(object source)
        {
            EventSource typedSource = (EventSource)source;
            typedSource.SomeEvent -= new EventHandler<SomeEventEventArgs>(OnSomeEvent);
        }
    
        /// <summary>
        /// Event handler for the SomeEvent event.
        /// </summary>
        void OnSomeEvent(object sender, SomeEventEventArgs e)
        {
            DeliverEvent(sender, e);
        }
    }
    
  2. SomeEventWeakEventManagerAdı kendi adınızla değiştirin.

  3. Daha önce açıklanan üç adı, olaylarınızın karşılık gelen adlarıyla değiştirin. ( SomeEvent , EventSource , ve SomeEventEventArgs )

  4. Zayıf olay Yöneticisi sınıfının görünürlüğünü (ortak/iç/özel), yönettiği olayla aynı görünürlüğe ayarlayın.

  5. Normal olay kancası yerine yeni zayıf olay yöneticisini kullanın.

    Örneğin, kodunuz bir olaya abone olmak için aşağıdaki kalıbı kullanıyorsa:

    source.SomeEvent += new SomeEventEventHandler(OnSomeEvent);  
    

    Aşağıdaki düzene göre değiştirin:

    SomeEventWeakEventManager.AddHandler(source, OnSomeEvent);  
    

    Benzer şekilde, kodunuz bir olaya abonelik kaldırmak için aşağıdaki kalıbı kullanıyorsa:

    source.SomeEvent -= new SomeEventEventHandler(OnSome);  
    

    Aşağıdaki düzene göre değiştirin:

    SomeEventWeakEventManager.RemoveHandler(source, OnSomeEvent);  
    

Ayrıca bkz.