ViewModel override

I had a talk with Kaj Lund from Attracts; they are using the ViewModels for WPF. He felt that the use of a DataGrid in every detail list is a bit “too much”. For example if there is only one column to display, and that you do not want to allow edit or allow user sorting a ListView might be a much more natural choice.

This is a dilemma for all declarative development; you often get a “one size fits all” scenario. Of course there is a way around it… Our take on declarative development aims to remove all the un-necessary degrees of freedom but still leave you in full command. In this case I suggested that Kaj should use the ViewModelWPFUserControl.OnColumnUIOverride event.

This event fires before each component is created and you can create your own based on the given circumstances. Probably you have a set of UI rules in you project like if the details grid only contains 1 column it should be a ListView instead (or whatever).

So this is one way to implement this event in xaml:

Code Snippet
  1. <vm:ViewModelWPFUserControl
  2.     OnColumnUIOverride="ViewModelWPFUserControl2_OnColumnUIOverride"
  3.     Height="180" x:Name="ViewModelWPFUserControl2"  
  4.     EcoSpaceTypeName="EcoProject1.EcoProject1EcoSpace"
  5.     ViewModelName="Building">
  6. </vm:ViewModelWPFUserControl>

And in code:

Code Snippet
  1. private void ViewModelWPFUserControl2_OnColumnUIOverride(object sender, Eco.ViewModel.Runtime.OnColumnUIOverrideArgs e)
  2. {
  3.     if (e.ViewModelColumn.StyleRef == "DisplayInListView" &&
  4.         e.ViewModelUIComponentType == ViewModelUIComponentType.grid &&
  5.         e.ViewModelColumn.DetailAssociation.Columns.Count>0)
  6.     {
  7.         e.ContinueWithDefault = false;
  8.         ListView lw=new ListView();
  9.         (sender as ViewModelWPFUserControl).LayoutGrid.Children.Add(lw);
  10.         lw.SetBinding(ListView.ItemsSourceProperty, new Binding() { Source = new EcoObjectDataProvider(e.ViewModelColumn.DetailAssociation.Handle) });
  11.         DataTemplate dt=new DataTemplate();
  12.         FrameworkElementFactory spFactory = new FrameworkElementFactory(typeof(StackPanel));
  13.         spFactory.Name = "factory";
  14.         spFactory.SetValue(StackPanel.OrientationProperty, Orientation.Horizontal);
  15.         FrameworkElementFactory tbfact = new FrameworkElementFactory(typeof(TextBlock));
  16.         tbfact.SetBinding(TextBlock.TextProperty, new Binding(e.ViewModelColumn.DetailAssociation.Columns[0].Name));
  17.         spFactory.AppendChild(tbfact);
  18.         dt.VisualTree = spFactory;
  19.         lw.ItemTemplate = dt;
  21.         Grid.SetColumn(lw,e.ViewModelColumn.XPos);
  22.         Grid.SetRow(lw,e.ViewModelColumn.YPos);
  23.         Grid.SetColumnSpan(lw, e.ViewModelColumn.ColSpan);
  24.         Grid.SetRowSpan(lw, e.ViewModelColumn.RowSpan);
  25.     }
  26. }


What the code does is in this case: 1. Verify that this column has the StyleRef==”DisplayInListView” and some other prerequisites that I decided should control the use of the ListView.

Then I set e.ContinueWithDefault=false to stop the standard behavior. And then I just add a ListView in the correct position and bind it to the data…

Voilá, we have extended our rule base for the declarative development provided by ViewModels.

This code went into the Buildings and Owners sample from the download; the bottom-right-grid was replaced with a ListView:

This entry was posted in ViewModel. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *