Combining Anonymous Types with Dynamic

Sunday, September 25, 2011 / Posted by Luke Puplett / comments (0)

This short blog post shows the outcome of a quick experiment. I am researching a way to back a WPF View with a ViewModel whose properties are not known until runtime.


It’s been a long time since I last blogged. I built a house, I’ve had a baby, well, Cassie did the hard work, and also worked on a very large Silverlight project for a large investment bank (a foreign exchange trading platform) and then moved again to a start-up in the West End of London.

The former job was all hush-hush and even though our small team had the pleasure of a couple of exclusive hours with Silverlight evangelist Mike Taulty, we weren’t able to tell him what we were working on. So blogging was out of the question, which is a real shame for me and the community as a whole, in my opinion (although understandable).

The Interesting Bit
Anyway, while playing this afternoon, I discovered that anonymous types can escape the confines of the scope they’re declared in by returning them as dynamic!
Check this out:
1 static void Main(string[] args) 2 { 3 var rows = ReadDynamicRows(); 4 5 foreach (var row in rows) 6 Console.WriteLine(row.Id); 7 8 object o = rows[0]; 9 var properties = o.GetType().GetProperties(); 10 } 11 12 private static List<dynamic> ReadDynamicRows() 13 { 14 dynamic row; 15 List<dynamic> rows = new List<dynamic>(); 16 using (var reader = 17 DataHelper.ExecuteSqlStatementReader( 18 DataHelper.BuildConnectionString(), 19 "SELECT TOP 1000 * FROM SomeTable")) 20 { 21 while (reader.Read()) 22 { 23 row = new 24 { 25 Id = reader.GetString(0), 26 }; 27 28 rows.Add(row); 29 } 30 } 31 32 return rows; 33 }


What’s really interesting to me is that the properties can be reflected upon. In my experiments with the dynamic type, this isn’t true and so databinding won’t work.


I don’t believe its that simple to stick them in an ObservableCollection bound to a DataGrid because the mechanics of it uses ICustomTypeDescriptor


More to come... (have a train to catch)

Labels: , ,

Recent Changes to vuPlan.tv Client

Thursday, October 07, 2010 / Posted by Luke Puplett / comments (0)

Since writing vuPlan.tv I’ve been using a placeholder company name ‘S26’ which I had to refactor to reflect my final company name Evoq Limited. The new codebase is built with new filenames and namespaces.

Also, the Windows 7 implementation of the Media Center API, at the COM interop level, has a memory leak. The new client works around the problem by creating an API shim inside a new AppDomain which gets recycled at intervals.

Finally, after seeing Mike Taulty’s session at UK Tech Days and his showing-off of new Metro-esque Windows 7 WPF applications Zune and MetroTwit, I reverted the vuPlan.tv client back into its Metro pyjamas. Previously I’d not done enough work on the shadow which is why it never really rocked my world; this version is much better I think.

vuPlan.tv Funkier Metro Look

Testing is on-going as it work on the web application/site. And that reminds me, I must update the images on the site.

Luke

Labels: , , , ,

My Gestural Listbox in WPF Wearing Windows Phone 7 Clothes

Wednesday, April 28, 2010 / Posted by Luke Puplett / comments (7)

Here's a dire quality video of a control that I hope to find time to blog about in the coming weeks. It's inspiration is obvious, it's execution was tough. Involved crash-learning Newtonian mechanics, solving equations and a bit of calculus.

Essentially, its a smart scrollviewer, so it can house all manner of controls; indeed I've uploaded one of a large image being panned with flicks and drags.

If enough people are interesed, I'll put the control up on CodePlex.

Labels:
, , , ,

WPF Font Rendering Side-by-side

Thursday, March 04, 2010 / Posted by Luke Puplett / comments (0)

Text rendering in Windows Presentation Framework has been a moot point since its release. Microsoft are responding to this and in WPF 4.0 text rendering will be performed by DirectWrite, some new bit of DirectX. But still, while working on reproducing a mockup done in Corel PHOTO-PAINT, I wanted to get to the bottom of why I am never happy with WPFs rendition and whether I am just imagining the whole thing.

My original mock-up was done in Corel's Photoshop equivalent at a very high resolution and then I view it in a normal viewer like Windows Live Photo Gallery and zoom it down to the right size.

I then compare my WPF work with the mockup PNG side-by-side and usually squint and shake my head alot.

So I created the same thing in CorelDRAW and Microsoft Word, giving me a total of 4 versions of the same mockup. Here's what I discovered.

Font Render Side-by-side

For me, Corel's versions are the nicest. I just like them more, in the way that I prefer one woman's face over another. It's subtle and innate.

Philosophy aside, the WPF version and the Corel could easily be mistaken for different typefaces. They're both Swiss 721 Lt BT. Here's my analysis:

  • Corel renders the O under the T, probably because it doesn't need to consider text selection. This is it primary advantage.
  • Corel apps and Word seem to render the lowercase glyphs slightly larger (1px) so that there is less of a difference in height to the uppercase T.
  • The top right end of the s in WPF sinks down, caused by confused anti-aliasing.
  • Word uses coloured anti-aliasing, blue on one side of the T and red on the other - the others do not.
  • WPF renders the thickest, most woolly lines.
  • WPF also renders the horizontal bar in e lower than the others, probably because it is slightly smaller and the bar snapped down a pixel.
Font Render Side-by-side Zoomed

As far as I see it, the fact that Microsoft Word can render the text quite accurately, the issue is not solely about ClearType but something inherent in WPF. It's a shame that text cannot be tuned per XAML element with varying amounts of anti-aliasing instead of on/off.

I hope they work it out in 4.0.

Labels: , , ,

Luke's Ridiculously Simple MVVM Table Grid

Friday, February 26, 2010 / Posted by Luke Puplett / comments (0)

Windows Phone 7 Series extends the panning and scrolling UI metaphors seen in Windows Media Center and apparently in the Zune. This is no surprise as they are consumer entertainment products, or at least two are and the phone has been remarketed.

Anyway, to experiment with this style of interface, which lends itself so well to touch, I realised that I need a kind of table that can slide left and right, scroll up and down, be extended dynamically and do all this from a control-agnostic view model. Welcome to my ridiculously simple custom control.

Reductionism

When thinking about designing a user interface one must adopt a reductionist mentality. Each consituent part of a UI needs breaking down into units of functionality and within each one, there are usually more units of functionality until a reusable control is arrived at. And then there's that control's constituents which are usually a small number of stock WPF controls.

This idea comes quite easily to an object oriented programmer because its pretty much the same thought process as for designing classes of logic.

To be useable from a ViewModel that is not aware of the control, perhaps because the assembly that the view model is in doesn't reference the library of custom controls, it must support data binding using CLR base types.

A table is a bunch of bunches of stuff and at the time of writing, there's only one bunch of stuff class that supports databinding and that's the ObservableCollection<T>.

The Phone 7 interface scrolls sideways between 'pages' of contextual content either by gesture or with a click of a 'column' header - itself in its own slider.

500x_xboxlivephone

Each page scrolls as a normal page, with autohide scrollbars like the iPhone. The simplest logical representation of this logic - remember controls are just logic - is a horizontal StackPanel of ListBox controls.

That harmoniously translates into CLR land as an ObservableCollection of ObservableCollection objects. Nice.

To allow of column headings, I'm going to wedge a KeyValuePair in there, where K is a string and V is the ObservableCollection<object>

Code

Here's the full code the control. I'll explain some of the few remarkable points after. However there is a bug bug in this quick attempt: DataBinding doesn't call the setter and so doesn't set the CollectionChanged handler, which is why it works in my non-bound example.

The solution is to add/remove the handlers for this event in the OnTableSourceChanged handler, but I'm sure most of you can work this out. Is that lazy? Sorry but editting formatted code in the published article is a nightmare.



namespace WpfSimpleTableControl
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Windows;
    using System.Windows.Controls;

    /// <summary>
    /// A StackPanel of ListBoxes where each ListBox represents a column of data which can be databound.
    /// </summary>
    /// <remarks>
    /// DataBinding works by mirroring the StackPanel of ListBoxes with an ObservableCollection of ObservableCollections.
    /// </remarks>
    public class SimpleTable : StackPanel
    {                  
        #region Constructors

        static SimpleTable()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(SimpleTable), new FrameworkPropertyMetadata(typeof(SimpleTable)));
        }

        #endregion

        #region Properties

        #region Dependency Properties

        public ObservableCollection<KeyValuePair<string, ObservableCollection<object>>> TableSource
        {
            get { return (ObservableCollection<KeyValuePair<string, ObservableCollection<object>>>)GetValue(TableSourceProperty); }
            set
            {
                var oldValue = this.TableSource;
                if (oldValue != null)
                    oldValue.CollectionChanged -= new System.Collections.Specialized.NotifyCollectionChangedEventHandler(table_CollectionChanged);

                value.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(table_CollectionChanged);
                SetValue(TableSourceProperty, value);
            }
        }
        public static readonly DependencyProperty TableSourceProperty = DependencyProperty.Register(
            "TableSource", typeof(ObservableCollection<KeyValuePair<string, ObservableCollection<object>>>), typeof(SimpleTable),
            new PropertyMetadata(
                new PropertyChangedCallback(OnTableSourceChanged)));

        public Style ListBoxStyle
        {
            get { return (Style)GetValue(ListBoxStyleProperty); }
            set { SetValue(ListBoxStyleProperty, value); }
        }        
        public static readonly DependencyProperty ListBoxStyleProperty =
            DependencyProperty.Register("ListBoxStyle", typeof(Style), typeof(SimpleTable), new UIPropertyMetadata(null));
        
        public DataTemplate ItemDataTemplate
        {
            get { return (DataTemplate)GetValue(ItemDataTemplateProperty); }
            set { SetValue(ItemDataTemplateProperty, value); }
        }
        public static readonly DependencyProperty ItemDataTemplateProperty =
            DependencyProperty.Register("ItemDataTemplate", typeof(DataTemplate), typeof(SimpleTable), new UIPropertyMetadata(null));

        #endregion

        #endregion

        #region Methods

        public void ReinitializeTableSource(ObservableCollection<KeyValuePair<string, ObservableCollection<object>>> table)
        {
            // Detach handlers and clear.
            //
            foreach(ListBox l in this.Children)
                l.LostFocus -= new RoutedEventHandler(listBox_LostFocus);
            //
            this.Children.Clear();
            
            if (table == null)
                return;

            foreach (var columnList in table)
            {
                string columnName = columnList.Key;
                
                var listBox = new ListBox();

                listBox.LostFocus += new RoutedEventHandler(listBox_LostFocus);

                if (this.ItemDataTemplate != null)
                    listBox.ItemTemplate = this.ItemDataTemplate;

                if (this.ListBoxStyle != null)
                    listBox.Style = this.ListBoxStyle;

                listBox.ItemsSource = columnList.Value;
                
                this.Children.Add(listBox);
            }
        }

        private void listBox_LostFocus(object sender, RoutedEventArgs e)
        {
            var listBox = (ListBox)sender;
            listBox.SelectedItem = null;
        }

        private void table_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            ReinitializeTableSource((ObservableCollection<KeyValuePair<string, ObservableCollection<object>>>)sender);
        }

        /// <summary>
        /// Reads properties and fires off the state changer using VSM.
        /// </summary>
        /// <param name="useTransitions">Whether to trigger animations between the states.</param>
        private void UpdateStates(bool useTransitions)
        {
            //if (this.IsFocused)
            //    VisualStateManager.GoToState(this, Ticker.FocusedStateName, useTransitions);
            //else
            //    VisualStateManager.GoToState(this, Ticker.UnfocusedStateName, useTransitions);
        }

        private static void OnTableSourceChanged(DependencyObject sender, DependencyPropertyChangedEventArgs args)
        {
            var newTable = (ObservableCollection<KeyValuePair<string, ObservableCollection<object>>>)args.NewValue;
            var control = (SimpleTable)sender;

            control.ReinitializeTableSource(newTable);
        }
        
        #endregion

        #region Control Overrides

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            // Grab named ControlTemplate assets and stick em in properties.
            //           
            //this.ScrollViewerElement = GetTemplateChild(SimpleTable.ScrollViewerPartName) as ScrollViewer;
            
            this.UpdateStates(false);
        }
        
        #endregion
    }
}

Starting at the top, it has no parts. This is because it derives from StackPanel and so it is just itself. It's just a panel.

Moving down the code, there are three DependencyProperty members. The first is the DataTable property which is typed as ObservableCollection<KeyValuePair<string, ObservableCollection<object>>>, the second is ListBoxStyle which accepts a Style object which allows such things as removing the default black border around each element and then there's ItemDataTemplate which is a DataTemplate to apply to each of the listboxes.

It's likely that each ListBox will need its own different DataTemplate but it would be quite trivial to add a property that takes a DataTemplateSelector which can use your own logic to work out which DataTemplate to apply to which items.

The next interesting thing is the ReinitializeTableSource method. This kicks out all the old ListBox instances in the panel (itself) and then adds new ones. It copies over the ItemDataTemplate and ListBoxStyle to each new ListBox and also hooks up the data binding to each collection that represents column data.

It also sets an event handler for the lostfocus event which simply removes the selection, otherwise each independant listbox will have its own selection highlight. There might be situations when this is useful, but not today.

Further down there's the handler for the main outer collection CollectionChanged event which can only really occur when columns are added or removed and triggers the whole thing to be reconfigured.

OnTableSourceChanged handles changes to the TableSource dependency property which could itself be bound, this also trigger a complete reconfig.

The rest is left over from the parts and states model and can support the VisualStateManager paradigm.

Basic Model

The most simple use of the control looks like this.

SimpleTable UI

The two buttons manipulate a window level private collection of collections which is communicated via the magic of data binding to the table on screen.

The XAML for the window is here:

<Window x:Class="WpfSimpleTableControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfSimpleTableControl"
Title="MainWindow" Height="350" Width="525">
<Grid>
<StackPanel>
<local:SimpleTable x:Name="SimpleTable" Margin="20" Orientation="Horizontal" Height="200">
<local:SimpleTable.ListBoxStyle>
<Style TargetType="{x:Type ListBox}">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Width" Value="150" />
</Style>
</local:SimpleTable.ListBoxStyle>
</local:SimpleTable>
<Button Width="150" Click="Button_Click" Margin="2">Add to column 2</Button>
<Button Width="150" Click="Button_Click" Margin="2">Add new column</Button>
</StackPanel>
</Grid>
</Window>

And the codebehind, which does not use MVVM for this simple demo, goes like this.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;

namespace WpfSimpleTableControl
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private ObservableCollection<KeyValuePair<string, ObservableCollection<object>>> _table 
            = new ObservableCollection<KeyValuePair<string, ObservableCollection<object>>>();

        public MainWindow()
        {
            this.Initialized += new EventHandler(MainWindow_Initialized);

            InitializeComponent();
        }

        void MainWindow_Initialized(object sender, EventArgs e)
        {
            var list = new ObservableCollection<object>();
            list.Add("Hello");
            list.Add("...world!");
            _table.Add(new KeyValuePair<string, ObservableCollection<object>>("Column1", list));

            list = new ObservableCollection<object>();
            list.Add("Latika!");            
            _table.Add(new KeyValuePair<string, ObservableCollection<object>>("Column2", list));


            this.SimpleTable.TableSource = _table;

            //this.SimpleTable.Background = Brushes.Gray;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var b = (Button)sender;

            switch (b.Content.ToString())
            {
                case "Add to column 2":
                    _table[1].Value.Add(DateTime.Now.Millisecond + b.Content.ToString());
                    break;

                case "Add new column":
                    _table.Add(new KeyValuePair<string,ObservableCollection<object>>("New Column"new ObservableCollection<object>()));
                    _table.Last().Value.Add("Default item.");
                    break;
            }
        }
    }
}

And with MVVM would really just be a binding in the XAML to a ObservableCollection<KeyValuePair<string, ObservableCollection<object>>> typed property on the ViewModel class.

Because this was designed with MVVM in mind, the clicking of items is not considered in the panel. Usually, the DataTemplate for the item binds a Command to a property on the item's ViewModel and so actions go direct.

I will return when I have made it look nice, added a DataTemplate and probably after discovering some minor nuance which completely trounces the whole thing's feasiblity and makes me look a tit.

Hopefully not though, maybe sometimes WPF can be simple. Maybe.

Labels: , , , , ,

Luke’s Guide to the ListBox Control

Tuesday, January 26, 2010 / Posted by Luke Puplett / comments (0)

This post is a copy (I'd cry if it got mauled) of the Community Content I added to the ListBox MSDN article explaining its highly complex model.

Every time I go to sleep I forget this, may I say, overly complicated beast of a control. Here's some community content that might help programmers of a similar disposition.

Right, a ListBox is a bunch of behaviours over the top of an ItemsControl which is essentially a controller for items in a Panel.

It's useful to consider its template which consists of a Border, a ScrollViewer (of which the ScrollViewer has a ScrollContentPresenter) and an ItemsPresenter.

This Panel can be changed via ItemsControl.ItemsPanel but could also be specified in the control template by adding your chosen Panel and setting its IsItemsHost=true which will hook it up to the ItemsControl/ListBox.

The ItemsControl's job is to generate the items according to customizable templates using an ItemContainerGenerator. For a ListBox, this makes ListBoxItem instances which are ContentControls and thus have ContentPresenters in their templates. Their look is affected using...

ItemTemplate. Simple except that it should not be used in conjunction with ItemTemplateSelector (which sets a DataTemplateSelector class that returns a DataTemplate when its SelectTemplate method is call and so you can add some kind of logic to determine which one to return).

And we're not done yet because there's also ItemContainerStyle and ItemContainerStyleSelector which do a similar job except that they style the container (ListBoxItem) around the item's actual rendered content (as defined by ItemTemplate).

As for the look of the highlight, I guess that's done as part of the template applied to the item in reaction to ListBoxItem.IsSelected. Probably.

[sigh] Whatever happened to HTML and CSS eh?

Labels: ,

Flowing Custom Control Values to ViewModel/Bindings

Friday, January 15, 2010 / Posted by Luke Puplett / comments (0)

This article discusses an issue I had when making a custom login box control, particularly the issue of getting the values in the username and password boxes to flow back down to the view-model. The issue might be my design, which could be fundamentally wrong, if only I knew of another way to do it.

The problem with Windows Presentation Foundation and its more promiscuous sister, Silverlight, is that its as good as it is bad. That is, its hard to deny its brilliance when you're carving out complex drawings and alpha gradients, adding subtleties to button animations and then there's the whole hardware accelerated 3D bit. But its bloody complicated because its mandate is to be everything to everyone and when so much is done for you all that stuff has to be massively multifaceted.

My LoginControl uses the parts and states model and the WPFToolkit to get at the VisualStateManager. I won't go into these things as they're documented enough and Karen Corby has a great MIX session video on it, too.

So I have a few parts, two TextBox controls and a Button. You can guess that these are username, password and the logon button.

Firstly, and I'll get this one over and done with quickly: I don't use the PasswordBox control. It does not support data binding because it takes a cautious approach and does things securely. Instead I apply a strikethrough formatting to a regular TextBox within its default style in generic.xaml.

You can see how this is done by reading my comments at the bottom of the MSDN article on the PasswordBox.

Welcome to my LoginControl

Cutting straight to the meat of the implementation, my control has the following properties:

  • private TextBox UsernameTextBox // the property which stores the TextBox UI control part/element for the username
  • private TextBox PasswordTextBox // the property which stores the TextBox UI control part/element for the password
  • public string Username // the dependency property which stores the username that can be bound to from a view model
  • public string Password // ditto but for the password

Because I can't bind my view model to a property of a the LoginControl's username TextBox and I don't want to expose the TextBox controls publicly, I use the following trick to hook up a binding between the TextBox.Text dependency property and LoginControl.Username (ditto for the password):

private TextBox UsernameTextBox
{
    get
    {
        return (TextBox)GetValue(UsernameTextBoxProperty);
    }
    set
    {
        // Detach observer from outgoing value.
        //
        var oldValue = this.UsernameTextBox;
        if (oldValue != null)
        {
            BindingOperations.ClearAllBindings(oldValue);
            oldValue.GotKeyboardFocus -= new KeyboardFocusChangedEventHandler(TextBoxes_GotKeyboardFocus);
            oldValue.KeyUp -= new KeyEventHandler(Username_KeyUp);
        }

        SetValue(UsernameTextBoxProperty, value);

        if (value != null)
        {
            value.SetBinding(TextBox.TextProperty, new Binding("Username")
            {
                Source = this,
                Mode = BindingMode.TwoWay
            });
            value.GotKeyboardFocus += new KeyboardFocusChangedEventHandler(TextBoxes_GotKeyboardFocus);
            value.KeyUp += new KeyEventHandler(Username_KeyUp);
        }
    }
}

And once that's done there's nothing else to consider except that when adding my LoginControl to my XAML page, I need to hook up the binding to the appropriate properties in the view model. That's easy:

Username="{Binding Path=Username, Mode=TwoWay}" Password="{Binding Path=Password, Mode=TwoWay}"

No worries there.

In Practice it Fails

The problem occurs when the login button is clicked and the ICommand is executed. The RelayCommand on the view model kicks in and my Action runs but if I stop the debugger right there I see that my view model does not have up-to-date Username and Password values!

My theory is that the binding system has not done its magic in between my typing of text and clicking of button. And although in theory the LostFocus events upon which data binding updates rely should have been triggered, my daisy-chained setup is somehow ballsing things up. Actually, there is a LostFocus on the username TextBox which should update the LoginControl.Username property, it doesn't, but even if it had, what's the activator to get the value to then jump from the Username property to its source down in my view model? By the way, flows up from source seem to work fine.

Whatever, I don't know. My solution was to grab each of my bindings and manually hit the UpdateSource method from within the login button's click method:

private void LoginButtonElement_Click(object sender, RoutedEventArgs e)
{
    var utbx = this.UsernameTextBox.GetBindingExpression(TextBox.TextProperty);
    utbx.UpdateSource();

    var ptbx = this.PasswordTextBox.GetBindingExpression(TextBox.TextProperty);
    ptbx.UpdateSource();

    var ubx = BindingOperations.GetBindingExpression(this, UsernameProperty);
    var pbx = BindingOperations.GetBindingExpression(this, PasswordProperty);

    ubx.UpdateSource();
    pbx.UpdateSource();

    if (this.PasswordTextBox != null)
    {
        if (!this.PasswordTextBox.IsFocused)
        {
            this.PasswordTextBox.Focus();
            if (!this.TryLoginButton.IsMouseOver)
                return;
        }
    }

    if (this.Command != null)
        this.Command.Execute(new KeyValuePair<stringstring>(this.Username, this.Password));
}

Which brings me right back to the point I made earlier about not doing this the right way. I'm not sure any other way would flow the values in time anyway. But then there's always the question of how everyone else doesn't seem to have this problem...

Labels: , , ,

How I Dynamically Load a ViewModel from the Web

Tuesday, January 12, 2010 / Posted by Luke Puplett / comments (0)

For my vuPlan client I wanted to avoid those 'update me' messages that Adobe products are good at annoying me with. My aim was to be able to tweak my application logic, perhaps fix bugs, and do it unobtrusively. I also wanted to maintain a typical execution context of an ordinary locally installed application. To be clear, I've not fully investigated the options open to me with ClickOnce, and recently I became a user of Seesmic Desktop which is the first time I've seen it used in the wild. But even if you have different design goals, here's how I do dynamic MVVM.

Objective

To download a compiled ViewModel class from the web at runtime and inject it into a local client application so that it hooks into the view just like a normal View-ViewModel does. Also to allow the last known good ViewModel to load when the web version is unavailable.

This article is not a complete code breakdown of the method, rather a 10,000ft overview with a few details. The concept is straight-forward enough for most OO programmers to get.

Overview

Dunno about you but I'm a visual learner and find graphics and diagrams more palatable than words alone. This schematic should compress most of what would otherwise be a long and arduous blog post into 1080x673 (if you look at the full size one I stuck on flickaarrrr).

Diagram of ViewModel class relationships

Each of the black-rimmed screen looking objects are ViewModel classes. The inheritence tree runs right to left and so rooted with ViewModel.cs.

This class is the base for all and every view model I use thoughtout my application and is very similar to the base VM Josh Smith defines in his excellent MSDN article on the Model-View-ViewModel pattern.

The only addition to Josh's base ViewModel worth mentioning is that I add a property (typed as object) which I used to store a reference to the Dispatcher for the UI control to which the ViewModel will be bound.

The coloured blocks define the code distribution in the sense of partitioning over assemblies. (A) is the actual WPF application executable/project and would reside on the client PC once deployed, (B) is the dynamically loaded assembly containing business logic and (C) is a reusable shared library.

The assemblies reference each other like so:

  • Assembly A references
    • The shared library C
  • Assembly B references
    • The shared library C
  • Assembly C references
    • Nothing other than the usual

The Shared Client .dll (C)

Two classes are defined in here. The abstract base ViewModel, as mentioned above, and an abstract base MainViewModel class. This latter class defines all the properties that the WPF view will bind to, but contains no other logic.

It also defines the ICommand properties into which behaviour and logic will be placed. This is an example of an ICommand to hook up to a Login button (in MainViewModel.cs):

public ICommand LoginCommand
{
    get
    {
        if (_loginCommand == null)
        {
            _loginCommand = new RelayCommand(param => this.Login(param), param => this.CanLogin(param));
            //_loginCommand = new RelayCommand(param => this.Login(param));
        }
        return _loginCommand;
    }
}
RelayCommand _loginCommand;
protected virtual void Login(object obj) { throw new NotImplementedException(); }
protected virtual bool CanLogin(object obj) { throw new NotImplementedException(); }

The RelayCommand comes straight from Josh Smith's article mentioned above. The key to it are the two virtual methods which will be overridden in the implementation assembly.

N.B. It may be possible to skip this class as I think WPF bindings are loosely coupled and not checked at build time. The XAML for my view simply contains lines like {Binding Path=Username} (for the username textbox) and so it stands to reason that any object instance could be set as the DataContext and binding/reflection will just work where it works and fail where it fails - although don't quote me on that.

I also define delegates for some actions such as closing the window or application which allows me to shift the implementation of that logic to where I know how I want it to work (in the application UI itself).

The Implementation Logic .dll (B)

I call this class MainImplViewModel and it contains an InitializeComponent method which in many ways is the main initializer for the application - remember that the UI assembly (A) is supposed to be 'dumb'.

For my app, it assigns some delegates and default property values. It also does things like checking if the internet is connected and altering property values which can affect whether various UI controls are active as well as loading stuff in from IsolatedStorage.

As mentioned above, I have a reference to the Dispatcher for the UI and so I also define utility methods for marshalling work onto that thread and my application also has a synchronisation process, so there's a private BackgroundWorker variable and event handlers there, too.

And of course, I override the methods that my RelayCommand objects rely on (in MainImplViewModel):

protected override bool CanLogin(object obj) { ... }
protected override void Login(object obj) { ... }

Within which is the actual implementation which can trigger UI changes by modifying the properties, starting my BackgroundWorker and all manner of stuff.

The Application UI XAML .exe

The job of the pared-down application code is to i) check we're online or that the local cache is available (Isolated Storage), ii) download the implementation assembly (B) from a URL and iii) load it.

Once loaded, the types defined in the implementation assembly are scanned and the first class of type MainViewModel that is found is instantiated and assigned to a local variable within the application as well as the DataContext of the main window.

I have written a pretty complex background component loader/initializer class but the main thrust of what its doing is simple; download the file from a website using an ordinary http get, then load the assembly from the raw bytes with Assembly.Load(bytes).

After this is done, it fires an event which continues the ViewModel load process and is handled like so (in app.xaml.cs):

void Initializer_AfterComponentLoaded(object sender, TypeLoadEventArgs e)
{
    if (e.Instance.GetType() == typeof(ResourceDictionary))
    {
        Application.Current.Resources = (ResourceDictionary)e.Instance;

        this.MainWindow = (Window)LoadComponent(new Uri(@"MainWindow.xaml", UriKind.Relative));
        this.MainWindow.Show();
    }
    else if (e.Instance.GetType() == typeof(System.Reflection.Assembly))
    {                
        UI.MainViewModel mainVm;
        if (this.Initializer.AssemblyLoader.TryLoadType<UI.MainViewModel>(out mainVm))
        {
            this.MainWindowViewModel = mainVm;
            this.MainWindow.DataContext = mainVm; // DataContext set to view model.
            
            mainVm.ShutdownApplicationAction = new Action<int>(ShutdownVuplan);
            mainVm.ScrollIntoViewAction = new Action(delegate
            {
                //var listBox = ((Window1)this.MainWindow).MainListBox;
                //if (listBox.Items.Count > 0)
                //    listBox.ScrollIntoView(listBox.Items.GetItemAt(listBox.Items.Count - 1));
            });
            mainVm.Dispatcher = this.MainWindow.Dispatcher;
            mainVm.ParentControl = this.MainWindow;

            this.SessionEnding += new SessionEndingCancelEventHandler(App_SessionEnding);

            mainVm.SyncStatusMessages.Add(Client.UI.StringHelper.TryGetWinFxResourceString("Status_Message_Initializing"));
            mainVm.InitializeComponent(this.CloudStatus); // Warning: Go To Definition will jump to base impl.
        }
        else
        {
            if (this.Initializer.AssemblyLoader.TypeLoadException != null)
                throw this.Initializer.AssemblyLoader.TypeLoadException;
        }
    }
}

I like to leave all my code around so you can get an idea of the other stuff I do. For example, my loader also loads a resource dictionary from the web, based on location – this is a subject for a different blog post, but you can see that I roll my own localization this way. The method above checks what type of object was loaded and if its an Assembly (the implementation assembly) it hooks it up.

What’s most important here is that I set MainWindowViewModel to point to the view model and then set the DataContext of my main window. Further down, I call the all important InitializeComponent and so any state changes to the view model made during this method will be reflected in the view.

To load a type from the implementation assembly I use a generic method TryLoadType<T>

public bool TryLoadType<T>(out T instance) where T : class
{
    this.TypeLoadException = null;
    instance = null;
    try
    {
        if (this.Assembly == null)
            throw new InvalidOperationException(UI.StringHelper.TryGetResourceString("ErrorMessages", "ErrorVitalReferenceIsNull"));

        foreach (Type t in this.Assembly.GetTypes()) // Exceptions here probably due to assembly dependencies of wrong version (remote assembly not latest build).
        {
            if (typeof(T).IsAssignableFrom(t))
            {
                instance = (T)this.Assembly.CreateInstance(t.FullName);
                // this.OnLoaded(new TypeLoadEventArgs(instance));}
            }
        }
    }
    catch (Exception e)
    {
        // Could throw any of 6 exceptions.
        //
        this.TypeLoadException = e;
    }
    return (instance != null);
}

The important bit here is the foreach loop that looks for the type specified in T. MainImplViewModel is derived from MainViewModel so the calling code only need know of the MainViewModel type and it will load the class with all the implementation logic.

The caller (in this case, the method above this one) can also set properties on the view model because it knows of the base type – this is why I have a MainViewModel (recall that I mentioned that in theory it could be excluded).

Conclusion

I've not the time to simplify my example code above, I've just ripped out lumps of code from my projects, thus making it more complicated and excluding things that may have made it more readable, sorry, but I think the general idea can be grasped by most programmers au fait with MVVM.

Using this technique, I can keep my business logic in an implementation assembly, fix bugs in it, and then publish the .dll file to a web server and my clients will be updated invisibly.

Which reminds me: remember to add an XCOPY command to the post build actions for the implementation DLL which copies the assembly to your web server. Easily forgotton - you'll wonder why your breakpoints aren't being hit.

Labels: , ,