Welcome to WindowsClient.net | Sign in | Join

The View Model is essentially a projection out of the model to make data-binding easier.  It’s one of those WPF things that makes life so much easier you cannot understand why a ViewModel class wasn’t created into the File|New WPF Project default template.  Before the ViewModel, spending a few months creating converters, wondering how many objects should go into a multi-bound converter and then keeping resource references up to date and named correctly, you really start to question this whole ‘declarative’ only model.

One problem that is still carried over from the world of 100 converters is synchronizing the GUI with model changes; that is making sure the GUI is hooked up to those INotifyPropertyChanged and CollectionChanged events coming out of your model.  This is especially important when you have data changing in your model in real-time.  This was tricky with Converters because you needed to make sure that the root bound object supported notifications and not the object being passed into the converter.  To get round this I’ve actually created a public “This” property on my model class just so the converter could use any property it liked from the object being bound and the view was correctly synchronized.

In the ViewModel world the trick is to make sure that INotifyPropertyChanged events get propagated back from the model through the ViewModel and into the View.  This means making sure the ViewModel subscribes to all its dependencies and re-raises the event for the View.  This can be quite tricky for ViewModel properties that are aggregate functions (like .Count or .Sum) and even worse if the ViewModel is a projection based on joins from multiple model collections.

I use a couple of ViewModel helper classes that do some of this event propagation.  There is nothing clever and there are better MVVM libraries out on the web, this is just to illustrate the point.  For a ViewModel base object I use the following generic class that is used to project from the UnderlyingModelType.

  1.     public class ViewModelObject<UnderlyingModelType> : ObservableObject, IDisposable where UnderlyingModelType : class, INotifyPropertyChanged
  2.     {
  3.         private UnderlyingModelType modelObject;
  4.         public ViewModelObject()
  5.         {
  6.         }
  7.         public ViewModelObject(UnderlyingModelType modelObject)
  8.             : base()
  9.         {
  10.             this.ModelObject = modelObject;
  11.         }
  12.         protected bool IsModelObjectNull
  13.         {
  14.             get { return (this.modelObject == null); }
  15.         }
  16.         virtual protected void OnModelObjectChanged(object sender, PropertyChangedEventArgs e)
  17.         {
  18.             UpdateViews();
  19.         }
  20.         public UnderlyingModelType ModelObject
  21.         {
  22.             get { return this.modelObject; }
  23.             set
  24.             {
  25.                 if (this.modelObject != null) OnUnsetModelObject(this.modelObject);
  26.                 this.modelObject = value;
  27.                 if (this.modelObject != null) OnSetModelObject(this.modelObject);
  28.             }
  29.         }
  30.         virtual protected void OnUnsetModelObject(UnderlyingModelType modelObject)
  31.         {
  32.             this.modelObject.PropertyChanged -= new PropertyChangedEventHandler(OnModelObjectChanged);
  33.         }
  34.         virtual protected void OnSetModelObject(UnderlyingModelType modelObject)
  35.         {
  36.             this.modelObject.PropertyChanged += new PropertyChangedEventHandler(OnModelObjectChanged);
  37.         }
  38.         {// on dispose disconnect from the model}
  39.         public virtual void Dispose()
  40.         {
  41.             this.ModelObject = null;
  42.         }
  43.     }

This class simply propagates NotifyPropertyChanged events from the source model object out to the View.  The underlying model object is accessed through the ModelObject property.

The fun starts with collections.  For this I need a ViewModel collection class that wraps a model collection and propagates INotifyCollectionChanged events.  The ViewModel collection needs to be a collection of ViewModel objects – not model objects.  The class below automatically creates these ViewModel objects for each new item in the underlying model collection – it essentially acts as a ViewModel factory based on the contents of an underlying model collection. This is effectively the same as a SQL View, where the row in the view is different to the underlying table but the contents are changing in real-time.

  1.     public class ViewModelCollection<T,TWrapped> : ObservableCollection<T>
  2.         where TWrapped : ObservableObject
  3.         where T: ViewModelObject<TWrapped>, new()
  4.     {
  5.         public IEnumerable<TWrapped> ModelCollection;
  6.         public ViewModelCollection(IEnumerable<TWrapped> collection)
  7.         {
  8.             this.ModelCollection = collection;
  9.             var notifyCollection = collection as INotifyCollectionChanged;
  10.             if (notifyCollection == null) throw new ArgumentException({"Must implement INotifyCollectionChanged"}, {"collection"});
  11.             notifyCollection.CollectionChanged += new NotifyCollectionChangedEventHandler(collection_CollectionChanged);
  12.             foreach (TWrapped item in collection)
  13.             {
  14.                 this.Add(new T() { ModelObject = item });
  15.             }
  16.         }
  17.         void collection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
  18.         {
  19.             if (e.Action == NotifyCollectionChangedAction.Add)
  20.             {
  21.                 foreach (TWrapped device in e.NewItems)
  22.                 {
  23.                     this.Add(new T() { ModelObject = device });
  24.                 }
  25.             }
  26.             else if (e.Action == NotifyCollectionChangedAction.Remove)
  27.             {
  28.                 foreach (TWrapped ob in e.OldItems)
  29.                 {
  30.                     var oldWrapper = this.FirstOrDefault(o => o.ModelObject == ob);
  31.                     if (oldWrapper == null) continue;
  32.                     this.Remove(oldWrapper);
  33.                 }
  34.             }
  35.             else
  36.             {
  37.                 this.Clear();
  38.                 foreach (var ob in this.ModelCollection)
  39.                 {
  40.                     this.Add(new T() { ModelObject = ob });
  41.                 }
  42.             }
  43.         }
  44.     }

This class is incomplete, it doesn’t efficiently deal with the different types of INotifyCollectionChanged events and it should really recycle ViewModel objects.  It does serve the basic function for being used in something like an ItemsControl on a Model collection where you really want to introduce a ViewModel object instead.

I could extend these classes to support some LINQ type queries on the underlying model.  You could imagine these projections becoming results from LINQ queries.  In fact, this is exactly what has been done in libraries like CLINQ already.  CLINQ offers the ability to create a declarative view-model based on a LINQ query.  If you’re looking at using a ViewModel on live data in a non-trivial model I would recommend you take a look at CLINQ on CodePlex.

The link in an old post about Pan & Zoom has broken.  This is the link to the Sky Drive files.  I also updated the code from a suggestion from Martin Rauscher that fixed a slight jitter.

The WPF team released an early version of the MVVM Toolkit as part of the WPF Futures project in CodePlex.

I just fired up a test project.  The download includes an application wizard that provides a barebones application with Commands, Models, ViewModels and Views solution folders.  The app wizard also asks to create a test project (like ASP.NET MVC).  The source code support is included in the solution, with a ViewModel ‘base’ class providing basic INotifyPropertyChanged support.

All looks pretty good for a first step.  Here’s what I’d like to see in the future:

  • The code walkthrough seems to follow the pattern of complete ViewModel abstraction.  This means that the ViewModel class re-exposes all properties from the underlying model.  I’m more pragmatic on this one, and prefer to have ViewModels that expose the underlying model type and only expose properties that project view specific data (like converter functions).  It would be great to see a ViewModel base class with support for property changed propagation (from model to view).
  • There doesn’t seem to be any support for ViewModel collections.  When you create a ViewModel you essentially have to maintain a ViewModel tree in parallel to the Model.  This is easy enough for static models, where a collection never changes; but if the data is dynamic then the ViewModel tree needs to stay in sync with the model.  There are a couple of solutions to this: - one is to have a ViewModel collection class that listens to the underlying model’s CollectionChanged notifications; another solution is to use something like CLINQ.  This provides complete collection projection to a ViewModel class wrapped around a model using a LINQ query.
  • Lastly, it would be great to see better designer support for ViewModels.  For example, what about generating the ViewModel property stubs based on the binding elements in a View?  In fact, most of the work the ViewModel does could be handled by a dynamic shim based on the View’s binding directives.  This would greatly reduce the labor intensive task of manually synchronizing of ViewModels to Models.

Just a few thoughts.  It would be great to see this in VS2010.

I recently took to converting a small side project from ASP.NET Dynamic Data, Web Services and WPF to ASP.NET MVC, ADO.NET Data Services and the Entity Framework.  The small project involved a small database, an administration web site and a smart client run over the Internet.  The dataset is small, the project is simple – just a single data source and no need for large enterprise style long term architectural planning.  But the goal is to gain some perspectives on the new technology and how it can be used in large scale multi-tier, multi-solution, multi-data source, enterprise wide architecture.  I’m trying to gauge how some of the new tools and wizards around this technology can be used alongside an enterprise architecture and common conceptual model.

This first tentative step is just one day in at this point.  Plus, this one day is with the distraction of the last few episodes of Battlestar Galactica on in the background.  So, please take any rants with a pinch of salt – it’s a work in progress. 

The Plan and the Tools

This small application has a small SQL Server database at its heart.  The data in the database is administered by an ASP.NET website.  The first step was to convert this from classic WebForms to ASP.NET MVC based on an Entity Framework data model.  The steps for this are covered well by the http://www.asp.net tutorials.  ASP.NET MVC by default does not give you the scaffolding that ASP.NET Dynamic Data gives you – but there’s a tool available that offers this functionality.  I stuck with the standard wizards and created my own views to edit/list/create/delete the four tables in the database.

The next step was to expose this data as a webservice.  I wanted to make this a URL friendly REST web service, so I added an ADO.NET Data Service to the ASP.NET project and pointed the service at the existing Entity Framework model.

Lastly, I needed to update the Rich clients to use the new web service.  To do this I used the client proxy "Add Service Reference” to the WPF app and also created a Silverlight 2 app using the same reference.

Entity Framework, Models and LINQ

In most scenarios having a single data source with the same schema as your application domain model is fine.  Your entity objects definitions are driven by your database design.  Entity objects are just a way of talking to your database. 

In enterprise architecture it can become much more complicated.  A typical ‘solution’ may have several data sources: – a legacy database, a new database that doesn’t quite cover all the new features that the old one did, a real-time transaction feed over a message bus, a security profile database, a vendor API onto another server etc.   On top of this there may be dozens of these solutions across multiple departments.  For Enterprise Architecture a more Domain Driven approach is required.  The Domain Model is built out of the business and not out of IT. 

Out of the box, the default use of the Entity Framework is in relation to a single data source.  There are some options for field mapping (new names, some versatility with data types etc) – but this is limited. The Entity Framework can support a conceptual model approach.  The EDMX file is composited of the SSDL (for storage), CSDL (for the conceptual model) and a mappings section bringing the two together. Unfortunately, the IDE doesn’t really support a CSDL only file.  It’s also not clear if a CSDL file can be used without the other components (I mean non-generated mapping and non-relational data source).

When you use the Entity Framework with a single relational datasource you get a generated set of entity objects (derived from EntityObject).  Diego Vega explains the layers of the Entity Framework nicely.  So far I don’t see this being extensible enough to provide support for a conceptual domain model approach, with multiple mappings to relational and non-relational data.  I guess this is where Oslo comes in.

A more general comment about technologies like the Entity Framework is that the assumption is the domain container is also the primary access point to the underlying data store.  A LINQ query on the ‘Orders’ collection on the container will actually go out to the preconfigured database.  From a multi-data source conceptual model perspective, I would prefer to see these Entity containers that represent the data source use conceptual data model classes rather than their own generated classes.  The Wizard for adding Web Service references has this feature (being able to reuse existing referenced types).

ASP.NET MVC and the Fork in the Road

I think MVC is generally easy to grasp.  The tutorial videos on www.asp.net are great, particularly this 12 minute video introduction.  I like the fact that MVC is decoupled from the underlying model and data access.  There are no real assumptions on LINQ to SQL, Entity Framework or even LINQ at all.  The Controller is in charge of this – as it should be.

On the downside, I got the ‘fork in the road’ feeling – even though Hybrids are possible, as detailed by Scott Hanselman.  I’m just one day in, but I totally failed to get an AJAX Web Service call to work using the DataView (using preview 4 of the ASP.NET AJAX bits).  This same call worked fine outside my view page.  I’m guessing it was a routed URL issue – and I will go back to review the ‘ignore route’ calls.  I don’t think there is anything inherently incompatible here, I just wish that there were fewer “New Project” options and more “Add File” options.  These technologies should be a toolbox and easy to pick and mix.

ASP.NET MVC and Entity Framework Foreign Keys

One pain point with MVC and the Entity Framework was around creating and editing relationships (foreign key columns).  The Entity Framework chooses to represent foreign key fields as an EntityRelationship object.  The default view creation fails and ignores these fields.  You can create a dropdownlist by hand, but the resulting value of the foreign key cannot be automatically mapped to the object (there’s no field to put it into).

There are a couple of solutions to this.  One solution that I’ve seen used is to use a ViewModel over the entity object.  Then create the view based on the viewmodel and use a local field to store the foreign key.  The other solution is to use a custom Controller function to pass back the newly created object, containing a parameter for the foreign key.  I’m not totally happy with either approach, but I think this is really a problem with the default generated Entity Model more than an MVC issue.

The Client Continuum

ADO.NET Data Services are great.  I especially like the client side support for LINQ – effectively giving you LINQ to REST.  I’m not sure how standard the URL syntax is (this is REST, there are no standards) but this is a huge time saver and a big boost for shops using the same technology platform on the client and server.

This ‘client continuum’ has massive potential.  This is especially important in areas where there is a lot of processing and the need to be flexible where that processing is run.

My plan for day#2 is to continue to refactor the code and focus on the client.  At the moment, my REST service reference in the Silverlight 2 and WPF client is using its own version of the entity objects that exist on the server.  There is no real code share (therefore hindering my ability to share other code that is built on the common conceptual model).  I want to be able to create a set of conceptual model classes, use them for the client side REST proxy and also use the same code on the server side in place of the generated Entity Framework classes.

I will cover this an share some code in a follow-up post. 

More on Twitter: @woodjoe.

Being a bit of the fan of the lab working coming out of Thirteen23 - I thought it was time to give Twitter a go with their Blu Twitter client. 

Follow me as woodjoe.

DeepZoom is a cool feature of Silverlight 2.0 allowing the user to zoom and pan around an image, while optimizing the bandwidth and how much of the image is downloaded.  The UI metaphor is potentially quite powerful - even outside of image viewing.  Take WPF, with its scalable vector content, panning and zooming around ad-hoc rendered content could have several uses - even without the dynamic image loading.

This quick post details how to achieve this is WPF with a simple ContentControl.  It borrows some functionality from Jaime Rodriguez's excellent DeepZoom Primer.

The entire pan and zoom functionality can be achieved by a single transform group.  I use a class derived from a content control with two transforms, a scale transform for zooming and a TranslateTransform for panning.  This transform group will then pan and zoom the content of the content control (much like the scroll viewer).  The initialization is done in code:

     this.source = VisualTreeHelper.GetChild(this, 0) as FrameworkElement;
      this.translateTransform = new TranslateTransform();
      this.zoomTransform = new ScaleTransform();
      this.transformGroup = new TransformGroup();
      this.transformGroup.Children.Add(this.zoomTransform);
      this.transformGroup.Children.Add(this.translateTransform);
      this.source.RenderTransform = this.transformGroup;

The DoZoom function modifies these transforms based on the parameters sent.  This is similar to Jaime's DoZoom function:

 /// <summary>Zoom into or out of the content.</summary>
 /// <param name="deltaZoom">Factor to mutliply the zoom level by. </param>
 /// <param name="mousePosition">Logical mouse position relative to the 
///
original content.</param>
/// <param name="physicalPosition">Actual mouse position on the screen
/// (relative to the parent window)</param>
public void DoZoom(double deltaZoom, Point mousePosition, Point physicalPosition) { double currentZoom = this.zoomTransform.ScaleX; currentZoom *= deltaZoom; this.translateTransform.BeginAnimation(TranslateTransform.XProperty,
CreateZoomAnimation(-1 * (mousePosition.X * currentZoom - physicalPosition.X))); this.translateTransform.BeginAnimation(TranslateTransform.YProperty,
CreateZoomAnimation(-1 * (mousePosition.Y * currentZoom - physicalPosition.Y))); this.zoomTransform.BeginAnimation(ScaleTransform.ScaleXProperty,
CreateZoomAnimation(currentZoom)); this.zoomTransform.BeginAnimation(ScaleTransform.ScaleYProperty,
CreateZoomAnimation(currentZoom)); }

The rest of the code simply hooks up the mouse events to the DoZoom function.  This is all self contained within the ContentControl, so using this Pan And Zoom functionality is simply a matter of adding the control and filling in the content.

It's still missing some functionality, like the navigation overlay.  It would also be nice to add events for the zoom detail so you could adjust detail of the rendered content based on the zoom level.

Source code can be found here

Updated this post and source code link here: http://blogs.windowsclient.net/joeyw/archive/2009/06/02/pan-and-zoom-updated.aspx

Ryan Stewart has a great post about where we are with the definition of RIA, and Scott Barnes continues.  A good enough topic for a first post here, here's my 5 cents from a developer of this technology for the past 15 years or so.

Taking a step back in time, when the Internet first blossomed into something more than just document access it presented something very different to traditional desktop applications.  Back then a desktop app was either a standalone document editor or a client/server line of business application.  An HTML web application was something different - it provided zero footprint deployment, hosted state (docs, settings etc), a security sandbox and completely different navigational patterns.  But, on the downside in this pre-AJAX world, every user action was responded to with a page refresh.  In those early days there were some moves to address this with Flash, Java Applets and even ActiveX. 

Generally speaking, I think we can define RIA as the move to address the lack of richness and interactivity in this new application model.  A RIA is a hybrid - combining 'traditional HTML' and desktop applications - the best features of both.  A RIA must follow the rules of the web model but include a better user experience:

  • Zero footprint deployment.  You don't need to go through a set-up or upgrade step.  Using the app won't change your machine in any way.  This doesn't mean it needs to run in a browser - that's just one way of discovering and running an application.
  • Security sandbox - you trust that the app won't have access to your system (unless through specific permission and UI guidance).
  • Supports a well defined server hosted application state - you store your data on the server by default.  (This could one day be invisible, with local files being synchronized back through to hosted state on a server).
  • The UX is rich enough so that it feels like a desktop application. 

This gives us a Spectrum of RIAness.  AJAX on one side, doing just enough interactivity and richness to look like a desktop app.  Going up the scale with Flash, Silverlight, Java and WPF XBAPs. 

Does a RIA need to be cross platform?  For some yes, for all - probably not.  For many this is just a factor of reach - especially if you include intranet or extranet applications.  If you needed to include cross platform as a requirement then which platforms?  How many?  Would you include devices?  Alarm clocks?  Refrigerators?

What is for sure is that all desktop applications will have to meet up to this definition in the future.  So RIA, as a definition, is dead - simply because we will just call them 'applications'.  

 
Page view counter