A Completely Dynamic View Model

December 29, 2011 at 11:43 AMAdministrator

Recently, I was working on a project where there was a requirement to print certain documents.  These documents were stored, in pieces, in the database and then loaded and assembled at runtime.  This allowed parts of the documents to be reused as needed.

The Xaml for these documents contained bindings to data that originated from the database.  The usual drill would be to statically define all the required properties on the view model and then write code to populate them from the database.  There's nothing wrong with this approach, but the project was in a mode where new documents were being generated quickly and they required new properties to be defined on the view model making the view model code a hot spot.

The data required in the bindings was largely stored as name/value pairs in the database.  Wouldn't it be much nice if new values added to the database just showed up at runtime without having to create new properties and the code to populate them?

Using dynamic objects would be a great way to go, if you could bind to them.  Unfortunately, they don't support reflection which is required for binding.  A second problem is that adding properties to a dynamic object requires a syntax like this:

Connect to XMPP
  1. dynamic vm = new object();
  2.             vm.PropertyName = 5;

Which, of course, requires you to know all property names to be added, ahead of time.  Since I'd like to be able to add properties that I find in the database, this is unsuitable.

I did some research and found this blog post by Lester Lobo.  The solution accompanying the post contained this class.

Connect to XMPP
  1. using System.Collections.Generic;
  2. using System.Collections.ObjectModel;
  3. using System.ComponentModel;
  4. using System.Dynamic;
  5. using System.Windows.Data;
  6. using System;
  7.  
  8. namespace DynamicVM
  9. {
  10.     public class DynamicObjectClass : DynamicObject, INotifyPropertyChanged
  11.     {
  12.         #region DynamicObject overrides
  13.  
  14.         public DynamicObjectClass()
  15.         {
  16.         }
  17.  
  18.         public override bool TryGetMember(GetMemberBinder binder, out object result)
  19.         {
  20.             return members.TryGetValue(binder.Name, out result);
  21.         }
  22.  
  23.         public override bool TrySetMember(SetMemberBinder binder, object value)
  24.         {
  25.             members[binder.Name] = value;
  26.             OnPropertyChanged(binder.Name);
  27.             return true;
  28.         }
  29.  
  30.         public override IEnumerable<string> GetDynamicMemberNames()
  31.         {
  32.             return members.Keys;
  33.         }
  34.  
  35.         public override bool TryGetIndex(GetIndexBinder binder, object[] indexes, out object result)
  36.         {
  37.             int index = (int)indexes[0];
  38.             try
  39.             {
  40.                 result = itemsCollection[index];
  41.             }
  42.             catch (ArgumentOutOfRangeException)
  43.             {
  44.                 result = null;
  45.                 return false;
  46.             }
  47.             return true;
  48.         }
  49.  
  50.         public override bool TrySetIndex(SetIndexBinder binder, object[] indexes, object value)
  51.         {
  52.             int index = (int)indexes[0];
  53.             itemsCollection[index] = value;
  54.             OnPropertyChanged(System.Windows.Data.Binding.IndexerName);
  55.             return true;
  56.         }
  57.  
  58.         public override bool TryDeleteMember(DeleteMemberBinder binder)
  59.         {
  60.             if (members.ContainsKey(binder.Name))
  61.             {
  62.                 members.Remove(binder.Name);
  63.                 return true;
  64.             }
  65.             return false;
  66.         }
  67.  
  68.         public override bool TryDeleteIndex(DeleteIndexBinder binder, object[] indexes)
  69.         {
  70.             int index = (int)indexes[0];
  71.             itemsCollection.RemoveAt(index);
  72.             return true;
  73.         }
  74.  
  75.         #endregion DynamicObject overrides
  76.  
  77.         public void AddProperty(string propertyName, object value)
  78.         {
  79.             members[propertyName] = value;
  80.         }
  81.  
  82.         #region INotifyPropertyChanged
  83.  
  84.         public event PropertyChangedEventHandler PropertyChanged;
  85.  
  86.         private void OnPropertyChanged(string propertyName)
  87.         {
  88.             if (PropertyChanged != null)
  89.                 PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  90.         }
  91.  
  92.         #endregion INotifyPropertyChanged
  93.  
  94.         #region Public methods
  95.  
  96.         public object AddItem(object item)
  97.         {
  98.             itemsCollection.Add(item);
  99.             OnPropertyChanged(Binding.IndexerName);
  100.             return null;
  101.         }
  102.  
  103.         #endregion Public methods
  104.  
  105.         #region Private data
  106.  
  107.         Dictionary<string, object> members = new Dictionary<string, object>();
  108.         ObservableCollection<object> itemsCollection = new ObservableCollection<object>();
  109.  
  110.         #endregion Private data
  111.     }
  112.  
  113. }

This class was almost just what I needed.  It solved the problem of not being able to bind to a dynamic, but I still needed a way to add properties on the fly.  For this, I added the AddProperty() method, which you'll see in the above listing.

Using the class is easy.  Below is an example.

Connect to XMPP
  1. AValue = new DynamicObjectClass();
  2.             AValue.Foo = "Hello"; //use the out-of-the-box syntax for adding a property
  3.  
  4.             AValue.AddProperty("Bar", 5); //add a property discovered at runtime.
  5.             AValue.AddProperty(propName, propValue);

So, using the above, I can simply read the name/value pairs out of the database and then add each to my view model at  runtime.  This means that any new value added to the database will automatically be available on the now dynamic view model for binding.

One Offs

Of course, you don't have to use a completely dynamic view model.  It's just as easy to define properties at design time and have one of those properties be a dynamic type.  Also, it's possible to have a dynamic view model that contains a property that is, itself, a dynamic.

Posted in: .Net | Database | WPF | dynamic

Tags: , , ,

An Introduction to KnockoutJS for XAML Developers

December 17, 2011 at 6:58 PMAdministrator

I've recently been working with KnockoutJS and have found it to be a very comfortable paradigm to use in constructing a web site.  Having worked with XAML a good bit over the last few years, the benefits of MVVM have been made apparent to me time and again and the approach is familiar.

KnockoutJS lets you use very nearly the same MVVM approach you're used to using in WPF or Silverlight development.  I've attached a sample application, below.  Let's have a look at it.

If you run the sample application, you'll see the following web page open in the browser.

RunningApp

There is an editable table that allows the user to edit existing contacts. Clicking the Add Contact button adds a new blank row to the table.

The ViewModel

The project contains a Javascript file named ViewModel.cs, in the Scripts directory.  The contexts of this file are listed below.

   1:  var viewModel = {
   2:      contacts : ko.observableArray([
   3:          { firstName : "Bob", lastName : "Marley" },
   4:          { firstName : "Larry", lastName : "The Cable Guy" },
   5:          { firstName : "Maxwell", lastName : "Smart" }
   6:      ]),
   7:   
   8:      addContact : function() {
   9:          this.contacts.push( { firstName : "", lastName : "" } );
  10:      }
  11:  }
  12:   
  13:  $(document).ready(function() {
  14:      
  15:      ko.applyBindings(viewModel); 
  16:  })
 
 

In the first code block, lines 1 – 11, we create a view model.  In WPF or Silverlight, out view model would contain properties and commands that we could bind to in our view.  The same is true with KnockoutJS.  Here, we have a property that is a collection of contacts and a function (command).  In lines 13 – 16, we ask Knockout to parse our view and connect the data bindings to our view model.

Notice that our property is an instance of an observableArray.  In XAML data binding, we have the concept of  the view and view model communicating with one another where events are raised when values change so that data and the controls bound to it stay in sync.  This same functionality is encapsulated in the observableArray for arrays and observable for simple properties.    So, modifying a bound property from the view model will cause a control in the view that is bound to the property to change, as well.  The reverse is also true, modifying the contents of the control will update the view model property.

The View

   1:  @{
   2:      Layout = null;
   3:  }
   4:   
   5:  <!DOCTYPE html>
   6:  <html>
   7:  <head>
   8:      <title>Index</title>
   9:      <script src="../../Scripts/jquery-1.5.1.js" type="text/javascript"></script>
  10:      <script src="../../Scripts/jQuery.tmpl.js" type="text/javascript"></script>
  11:      <script src="../../Scripts/knockout-1.2.1.js" type="text/javascript"></script>
  12:      <script src="../../Scripts/ViewModel.js" type="text/javascript"></script>
  13:  </head>
  14:  <body>
  15:      <div>
  16:          <fieldset>
  17:              <legend>Email Addresses</legend>
  18:   
  19:                  <table>
  20:                  <thead>
  21:                      <tr>
  22:                          <th>First Name</th>
  23:                          <th>Last Name</th>
  24:                      </tr>
  25:                  </thead>
  26:                  <tbody 
  27:                    data-bind='template: { name: "contactRowTemplate", foreach: contacts }'>
  28:                  </tbody>
  29:              </table>
  30:   
  31:              <button data-bind="click: addContact">Add Contact</button>
  32:   
  33:              <script type="text/html" id="contactRowTemplate">
  34:                  <tr>
  35:                      <td><input class="required" 
  36:                          data-bind="value: firstName, uniqueName: false"/></td>
  37:                      <td><input class="required" 
  38:                          data-bind="value: lastName, uniqueName: false"/></td>
  39:                  </tr>
  40:              </script>
  41:   
  42:          </fieldset>
  43:      </div>
  44:  </body>
  45:  </html>
 

We start by setting up our html table.  All probably looks familiar up to line 27.  In Xaml, we use Binding expressions to state what we want to bind to and how that binding is to behave.  KnockoutJS uses the "data-bind" attribute to specify these bindings.  In line 27 a binding is expresses that says, "for each item in the collection of contacts on the view model, create and populate an instance of the template named 'contactRowTemplate'".  You can see the template definition in lines 33 – 40.

Compare this binding with a similar Xaml binding and you'll find:

  • It's possible to do an ItemsSource type binding in KnockoutJS where an item is generated for each entry in an array.
  • Adding or removing an item from the array causes row corresponding to that item to appear or disappear respectively.
  • A template can be specified for how each item in the list will be constructed.  Compare this with the ability to specify an ItemTemplate in Xaml (note that you can organize the container of the list as you wish which is very similar to ControlTemplate's.
  • In Xaml, the data context flows in a predictable way through all an item's sub-items.  Note that the binding on the <tbody> element is to an array and the bindings inside the template are to a single item in the array.  This behaves the same as in Xaml.

The button in line 31 uses a click binding to bind the click event to the function we defined on our view model.

Yes, the binding syntax is different and there are many more binding types available than are used in this simple sample, but the library is very well documented here and the familiarity of the MVVM approach to constructing a UI make KnockoutJS a very easy library to get started with.

Download File - KnockoutSampleSolution

Posted in: .Net | ASP.Net | JavaScript | Silverlight | WPF

Tags: , , , ,

Dynamically Loading XAML

November 14, 2011 at 4:13 AMAdministrator

Occasionally it's useful to be able to load a piece of XAML as a string. This allows you to be able to decide, at runtime, what the UI will look like. This XAML can be composed beforehand and stored away in a file or the database, or it can be generated on-the-fly at runtime. In any case, the XAML can be a simple string and loaded into the the visual tree at runtime.

There are a few things you'll need to keep in mind, however.

Remove the Class attribute

The Class attribute is specified on the root element of a XAML document and specified the code file containing the code-behind code that is associated with the document. If this attribute is specified, it is expected that the class exists. Using code-behind kind of defeats the purpose of dynamically loading your XAML.

Explicitly Specify Namespaces and Assemblies

A good rule of thumb is that if you have to add a namespace to your document in order to be able to access its contents, you need to also specify the assembly containing the namespace. For example:

xmlns:cnvtr="clr-namespace:MyConverters.Sub.Xaml.Converters;assembly=MvcConverters"

 

Load the XAML

Once you have clean XAML in a string format, you can load it as below:

            var stringReader = new StringReader(value);
            var xmlTextReader = new XmlTextReader(stringReader);
 
            var control = XamlReader.Load(xmlTextReader);

In the above, "value" is a string that contains the XAML. We set it ass the source of a StringReader, which is set as the source of an XmlTextReader. This is passed into the XamlReader's Load method. Here, the XAML is parsed and a visual tree is constructed.

The Load method returns the root element of your control as a type "object". All that's left to do is to either set the control's DataContext or inject it into an already existing visual tree through, say, binding.

Posted in: .Net | WPF

Tags: , , ,

The Value of Converters

December 1, 2009 at 5:55 AMmgordon

Over time, I’ve discovered more and more uses for value converters in my Silverlight and WPF applications.  In this post, we’ll look at what they are and some scenarios where they are useful.

What are value converters

If you’ve done any development in Silverlight or WPF, you know that when using these technologies, the user interface is specified in XAML, a dialect of XML.  Since we are using XML, or essentially strings, to defined our GUI the XAML parser needs to know how to turn the strings we specify into types.  For example, when we specify at attribute on a control such as IsEnabled=”True”, there needs to be away for the string “True” to be understood as a Boolean value.  When we say Background=”Black”, the string “Black” needs to be understood as Brush of color #FF000000. 

Both of these examples are common occurrences so there are built in converters that take care of these.  However, in our applications, there are likely going to be cases where we need to specify a value that the XAML parser has no idea how to interpret.  For these cases, we can create our own value converter to specify what type a string needs to be converted to.

An Example

Suppose you have a DataGrid in your UI that contains orders.  Each of these orders has a status property and you want to display an icon in each row that depicts the status of the order.  The grid is bound to a collection in the ViewModel.  How do you achieve this?

 

First, you’d need to define the column for the icon.  Perhaps, something like below.

<data:DataGridTemplateColumn Header="Status" CellTemplate="{StaticResource statusTemplate}" 
                                            IsReadOnly="True" Width="50" 
                                            CanUserSort="False"/>

 

Here, we specify the column’s layout in a template, statusTemplate.

<DataTemplate x:Key="stausTemplate">
    <Image Height="32" Width="32" Source="{Binding StatusCode, Converter={StaticResource statusToImage}, 
        Mode=OneWay}"/>
</DataTemplate>

 

In our template, we’re specifying an Image element, but binding its Source property to the status code.  Somehow, that status code has to be converted into a reference to an image file.  To handle that conversion, we specify a converter in our binding.  Let’s look at how to implement that converter.

To start, we need to create a new class and have it implement the interface IValueConverter.  Our class would look like this.

public class StatusToImageConverter : IValueConverter
    {

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, 
            System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        public object ConvertBack(object value, Type targetType, object parameter, 
            System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

 

Implementing the IValueConverter interface requires us to implement two methods, Convert and ConvertBack.  The Convert method will be called to convert the original value to the desired value.  In our example, this method will be responsible for converting the status code to and image reference.  The ConvertBack method, does just the opposite.  If the converter is used in a TwoWay binding, the ConvertBack method will be called to convert a value specified back into a value of the original type.  In other words, if in our example the user were able to select an image, that image would be converted back into a status code before being pushed back into the order.

In our case, we’re only interested in using the converter in a OneWay binding, so we can leave the ConvertBack method un-implemented.  The finished class might look like the below.

public class StatusToImageConverter : IValueConverter
    {

        #region IValueConverter Members

        public object Convert(object value, Type targetType, object parameter, 
            System.Globalization.CultureInfo culture)
        {
            char statusCode = value.ToString()[0];

            switch (statusCode)
            {
                case 'A':
                    return "/Images/active.png";
                case 'W':
                    return "/images/working.png";
                case 'F':
                    return "/images/filled.png";
                case 'P':
                    return "/Images/paid.png";
            }

            return null;
        }

        public object ConvertBack(object value, Type targetType, object parameter, 
            System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }

        #endregion
    }

 

With the converter built, we just need to reference it in our XAML as a resource.

<converters:StatusToImageConverter x:Key="statusToImage"/>

 

Other Uses

What if in our grid, we also have a column that contains a dropdown containing the shipper that we will be using to ship our order.  The ItemsSource for the dropdown is bound to a collection of Shipper objects and its SelectedValue property is bound to a ShipperId.  That shipperId needs to be converted into a Shipper object in order for the binding to work.  Using what we know about value converters, we can create a converter that takes the id and looks up the corresponding object in a list.

Converters are incredibly flexible and powerful allowing you to inject logic into your UI easily.     

Posted in: Silverlight | WPF

Tags: ,