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:

publicinterfaceIStockQuoteProvider

{

///<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, outdouble 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:

publicclassStockModel : 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(newWaitCallback(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!

publicstring Symbol

{

get { return _symbol; }

}

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

publicdouble Quote

{

get

{

VerifyCalledOnUIThread();

return _quote;

}

privateset

{

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.

privatevoid FetchQuoteCallback(object state)

{

double fetchedQuote;

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

{

this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,

newThreadStart(delegate

{

this.Quote = fetchedQuote;

this.State = ModelState.Active;

}));

}

else

{

this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle,

newThreadStart(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:

privatestring _symbol;

privatedouble _quote;

privateIStockQuoteProvider _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.

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.

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.

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!?

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.