I’ve been continuing to dabble with my little status app (described here and here). I wanted to write down some of the lessons learned so far. Also, I think I have a decent plan for how to finish this app too.
Models and ViewModels (MVVM):
As you may recall, this is a WPF application that is using the MVVM pattern for separating the data from presentation. You may also recall that each window/control/page/etc can have exactly one DataContext. Also consider that user controls will have access to the parent DataContext, if you want.
So, from a video I saw, that is what I was originally doing. I had a directory for Twitter, Mail, Weather – and in there were the models, viewmodels, and user controls for that respective functionality. However, from the main window, I had sort of a "container" viewmodel that referenced those sub-viewmodels.
The first problem was because the user control doesn’t have it’s own, direct DataContext, that means that you won’t be able to see what the control looks like at design-time. That isn’t a showstopper, but wasn’t ideal. That meant that I couldn’t just "Apply Databinding" from the property window, instead I’d have to type the XAML. In other words, the DataContext was implied at run-time, but not explicit at Design-Time – which means I couldn’t use the nice little time-savers in the IDE.
Also, as I was refactoring and cleaning up some code, it became apparent to me that "window", shouldn’t be controlling everything. Each user control is capable – and it’s ideal even, if it manages it’s own DataContext. In this particular case, that makes more sense because there isn’t really anything common between these pieces of functionality.
So I refactored each piece of functionality into it’s own user control – even the date and time. Now, every user control has it’s own (local) DataContext. That means that in design-time, I actually see working functionality. For example:
This is what I have now for a structure:
Polling and Timing:
Now that each user control has it’s own DataContext, it seemed logical to put my polling logic in the ViewModel. So each ViewModel uses a DispatcherTimer. On the Tick event, it checks to see how long it’s been since the last poll. Once a certain period has passed, it refreshes the data.
In the case of the datetime, I do that once per second. For Twitter, I do that once ever 150 seconds. For weather, I do once per-hour, at :15 after the hour. Lastly, for mail, I have been going back and forth with a couple of components, but ultimately when I get something working the way I want, I’ll likely poll every :15 minutes, if I use POP3. If I use IMAP, I shouldn’t need to poll and will instead be notified when there is new mail.
While I was at it, I realized that it was slightly annoying not knowing how stale the data was on the screen. So – since each ViewModel knows how long it’s going to be until it refreshes the Model again, I decided to expose a property, that I bind to a progress bar. I didn’t want to get too obnoxious with the progress bar’s, but I wanted something kind of subtle. I think this works well:
As you might imagine, the progress bar under the time moves every second where :60 seconds is 100%. For weather, that polls once per hour (because the feed is only updated once per hour) – so that inches along throughout the hour. For twitter, that one moves a little faster where 100% is 150 seconds (2.5 minutes). Anyhow, I kind of like this. It not only shows me the status of these key things, it shows me the status of when these key things will be updated next!
First, I’ve tried maybe 5 different POP3 and IMAP .NET components – all open source. They all have at least one major flaw each. 3 outright didn’t work, the others had significant bugs. I need to get that hammered out. Now that I transitioned to gmail, I can now (in theory) use IMAP, which is much more powerful – but also more complicated.
Anyhow, aside from that, the one last thing I’d like to do is make this all configurable. Right now, much of the settings are hard-coded. For example, the URL for the weather for my town, my authorization code for twitter, and the credentials for getting mail are all hard-coded at the moment. Instead, I’d obviously like to have those be user settable.
How I plan to approach that is as follows. Since each user control (twitter, mail, time, and weather) are completely self-sufficient, and since they control their own screen real estate, I could just put the config settings IN the place where the control is. For example for weather – if the current user hasn’t chosen a location, instead of showing all that information, maybe that area of the screen just has a city dropdown, and "Save" button. When they click save, then the control shows what’s up there now. Same for twitter, email, etc. The core settings would be set, in the existing space. You could alter those settings maybe with a little button or icon in the top-right of each control. At least, that’s what I have in my head. That would really be the last step where I could then actually share this source code. I’ve talked to several other developers about this, and this is simple enough, but also complete enough to be a decent reference-architecture application to show how to do MVVM with WPF. So ultimately, I’d like to finish cleaning it up and then share the source.
That’s it for now. Once I get the mail piece straightened out – and maybe if I can figure out how to make these sections user-configurable, I will clean up the project a bit, do some documentation and I’ll post back with my final lessons learned on it. That probably won’t be for a week or more, but that’s the goal…