Best Practices: How to implement INotifyPropertyChanged right?

Jó összefoglaló a témában.

Update: ez lett a vége:


using System.ComponentModel;
using System.Threading;
using Krs.Ats.IBNet;

namespace ATS.IB
{
    /// <summary>
    /// Real-time data descriptor for IB tick data
    /// </summary>
    public class MarketData : INotifyPropertyChanged
    {
        public Contract IBContract { get; set; }
        public Ticker Ticker { get; set; }

        private decimal lastPrice;
        public decimal LastPrice
        {
            get { return lastPrice; }
            set
            {
                lastPrice = value;
                OnPropertyChanged(LastPriceChangedArgs);
            }
        }

        private decimal lastBid;
        public decimal LastBid
        {
            get { return lastBid; }
            set
            {
                lastBid = value;
                OnPropertyChanged(LastBidChangedArgs);
            }
        }

        private decimal lastAsk;
        public decimal LastAsk
        {
            get { return lastAsk; }
            set
            {
                lastAsk = value;
                OnPropertyChanged(LastAskChangedArgs);
            }
        }

        private int lastSize;
        public int LastSize
        {
            get { return lastSize; }
            set
            {
                lastSize = value;
                OnPropertyChanged(LastSizeChangedArgs);
            }
        }

        private int lastAskSize;
        public int LastAskSize
        {
            get { return lastAskSize; }
            set
            {
                lastAskSize = value;
                OnPropertyChanged(LastAskSizeChangedArgs);
            }
        }

        private int lastBidSize;
        public int LastBidSize
        {
            get { return lastBidSize; }
            set
            {
                lastBidSize = value;
                OnPropertyChanged(LastBisSizeChangedArgs);
            }
        }

        private static readonly PropertyChangedEventArgs LastPriceChangedArgs = ObservableHelper.CreateArgs<MarketData>(x => x.LastPrice);
        private static readonly PropertyChangedEventArgs LastBidChangedArgs = ObservableHelper.CreateArgs<MarketData>(x => x.LastBid);
        private static readonly PropertyChangedEventArgs LastAskChangedArgs = ObservableHelper.CreateArgs<MarketData>(x => x.LastAsk);
        private static readonly PropertyChangedEventArgs LastSizeChangedArgs = ObservableHelper.CreateArgs<MarketData>(x => x.LastSize);
        private static readonly PropertyChangedEventArgs LastBisSizeChangedArgs = ObservableHelper.CreateArgs<MarketData>(x => x.LastBidSize);
        private static readonly PropertyChangedEventArgs LastAskSizeChangedArgs = ObservableHelper.CreateArgs<MarketData>(x => x.LastAskSize);

        private void OnPropertyChanged(PropertyChangedEventArgs e)
        {
            var eventHandler = PropertyChanged;
            if (eventHandler != null)
            {
                if (guiSyncContext != SynchronizationContext.Current)
                {
                    guiSyncContext.CallOnMainThread(OnPropertyChanged, e);
                }
                else
                {
                    eventHandler(this, e);
                }
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private SynchronizationContext guiSyncContext = SynchronizationContext.Current;

        public void SetGuiSyncContext()
        {
            guiSyncContext = SynchronizationContext.Current;
        }
    }
}

6 Responses to “Best Practices: How to implement INotifyPropertyChanged right?”

  1. DFulop Says:

    Whoa! Szép; erre a megoldásra nem is gondoltam. Two thumbs up. :)

  2. Szindbad Says:

    1, Az eventargot becachelni? Mi a vérért?
    2, Event dobás thread safety már nem játszik? (pspidey legalább figyel erre)

    Szvsz a legelegánsabb megoldás bitbonké, viszont nem tudom, hogy ez mennyi overheaddel jár.

  3. Soczó Zsolt Says:

    1. Hogy ne dolgozzon olyan sokat a GC. Mpként 50e event esetén rendesen szemetel a sok, ugyanolyan eventarg.
    A bitbonkos megoldás jó üzleti appban, ahol ritkán vannak események. De az expression szétszedése felesleges overhead lenne nálam.

  4. storm12 Says:

    “Event dobás thread safety már nem játszik? (pspidey legalább figyel erre)”

    var eventHandler = PropertyChanged;

    Mivel az event immutable, így elméletileg ez jó megoldás, de a CLR via C# v3 ban azt írják (262 oldal), hogy ezt esetleg a későbbi fordítók ezt kioptimalizálhatják, ezért célszerűbb ezt alkalmazni.

    var eventHandler = Interlocked.CompareExchange(ref PropertyChanged, null, null);

  5. storm12 Says:

    264. oldal

  6. Gubus Says:

    Szia!

    A set-nél miért nem érdemes ellenőrizni, hogy az érték tényleg változott-e, és csak akkor küldeni az eseményt?
    Köszi.

    G.

Leave a Reply