DM-V-VM part 3: A sample DataModel


In part 2, I showed a base class for DataModels. In this post, I will describe a sample implementation. For this sample, I’ll use a DataModel that represents a stock. The model will be in charge of asynchronously fetching the stock quote and making it’s value available.

As part of making this class more testable, we first define an interface for retrieving stock quotes:

    public interface IStockQuoteProvider

    {

        /// <summary>

        /// Get a quote. This function may block on slow operations like hitting the network.

        /// </summary>

        /// <param name=”symbol”>The stock symbol.</param>

        /// <param name=”quote”>The quote.</param>

        /// <returns>Whether we were able to get a quote.</returns>

        bool TryGetQuote(string symbol, out double quote);

    }

This will let us plug in mock providers for unit testing. Let’s walk through the model implementation. First the class declaration and constructor:

    public class StockModel : DataModel

    {

        public StockModel(string symbol, IStockQuoteProvider quoteProvider)

        {

            _symbol = symbol;

            _quoteProvider = quoteProvider;

 

            this.State = ModelState.Fectching;

 

            // Queue a work item to fetch the quote

            if (!ThreadPool.QueueUserWorkItem(new WaitCallback(FetchQuoteCallback)))

            {

                this.State = ModelState.Invalid;

            }

        }

The constructor takes the stock symbol and the quote provider. It sets the initial model state to fetching and queues a work item to be called on a background thread. Don’t forget to check the return result of QueueUserWorkItem! If it fails, the model will be put in the invalid state.

Next, the symbol property. This one is simple!

        public string Symbol

        {

            get { return _symbol; }

        }

For the quote property, we’ll have a private setter that will send the property changed event:

        public double Quote

        {

            get

            {

                VerifyCalledOnUIThread();

 

                return _quote;

            }

 

            private set

            {

                VerifyCalledOnUIThread();

 

                if (_quote != value)

                {

                    _quote = value;

                    SendPropertyChanged(“Quote”);

                }

            }

        }

Now, here’s the callback to fetch the quote. Remember, this will be called on a background thread where it’s okay for us to do expensive operations like hitting a web service to get a quote.

        private void FetchQuoteCallback(object state)

        {

            double fetchedQuote;

            if (_quoteProvider.TryGetQuote(_symbol, out fetchedQuote))

            {

                this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,

                    new ThreadStart(delegate

                    {

                        this.Quote = fetchedQuote;

                        this.State = ModelState.Active;

                    }));

            }

            else

            {

                this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,

                    new ThreadStart(delegate

                    { this.State = ModelState.Invalid; }));

            }

        }

We need to dispatch back to the UI thread to set the properties. This avoids any complex locking logic and makes sure that all of the property changed events come from the UI thread.

Finally, we just have the fields:

        private string _symbol;

        private double _quote;

        private IStockQuoteProvider _quoteProvider;

    }

So, that’s it! What we’ve got is a class that’s perfectly suited to being displayed in a WPF DataTemplate. It’s got the symbol and quote available for binding. And, the state can be used in a trigger to change the look while it’s fetching or if there’s an error. The UI thread will never be blocked on slow operations.

Next up, I’ll show some unit tests for this class, which will show you how to unit test code that uses a dispatcher.

Comments (8)

  1. In part 3, I showed code for StockModel, a DataModel for stocks. On the Max team, we are big believers…

  2. Joe says:

    Not sure about the way you tied the retreival logic with the model state.

    I would preferred you model the data in one class (and collections of that data) and then model the service that populates that data in another.  This way you separate the data away from performing a function on that data.  Even worse this logic retreives just one quote – what happens when you want to retreive a portfolio of quotes.  You would need to put this logic into the Quote container.

    You could argue that different sources of data would all support the same interface – IStockQuote.  It just seems to be better practice to force the boundary between the retrieval of the data and the state itself to be more explicit.  It’s not common practice now to derive from ADO’s DataSet and add your database functions in there.  In general seperating state from program logic lends itself to more scalable solutions.

  3. dancre says:

    Good feedback. It would probably have been better to also show a factored out StockQuote class that just contains the raw data. I think that’s a more typical pattern. The quote provider can have the logic to batch up queries, but it really hasn’t been given enough information to do so properly in this case.

    The big advantage to having the model control when to retrieve the data is that it helps with virtualization. However, the way I wrote it in this example, you don’t get that advantage. Hold on and I’ll show a more realistic example where we only fetch the expensive data when the DataModel is visible in the UI. This is a key piece of the pattern that I left out.

  4. I’ve noticed that in the sample here you retreive the stock information inside a thread…. What happens with the following scenario:

    You need to fetch a photo prom the internet (let’s say a larg photo that it will take at leaset 10 secs to download). That image is loaded into a BitmapImaga object. This means that inside a thread you need to catch the DownloadCompleted event…. But if the thread is completed before the event is fired it will be destroyed and you will not have the image stored in that object… So how would you suggest to have that event captured inside the thread, so that the thread is not destroyed before the event is fired…. Or I am missing something!?

  5. dancre says:

    If you are doing an expensive operation like fetching an image over the network, there are basically two approaches. One is to do it synchronously on a background thread and the other is to use the asynchronous APIs. If you are using the asynchronous APIs, there’s no need to set up your own background thread. Just dispatch the results to the UI thread in your DownloadCompleted event.

  6. If you’re doing WPF development, you really need to check out Dan Crevier ‘s series on DataModel-View-ViewModel.

  7. I thought I should add a post with the full list of posts in the D-V-VM pattern. They are: DataModel-View-ViewModel

  8. In part 3 , I showed code for StockModel, a DataModel for stocks. On the Max team, we are big believers