ExpandoObject in Silverlight – Take 2

In my previous blog we looked how easy it to use dynamic / ExpandoObject in Silverlight. But if you notice the sample code, I cheated big time there. Even though I created a dynamic class on the fly, the binding did happen to a known properties of the ViewModel. Have a look at the XAML I used in the previous example

Code Snippet
  1.  
  2. <TextBlock Text="First Name" FontSize="14"/>
  3. <TextBlock Text="{Binding FirstName}" FontSize="14" Grid.Column="1"/>
  4. <TextBlock Text="Last Name" FontSize="14" Grid.Row="1"/>
  5. <TextBlock Text="{Binding LastName}" FontSize="14" Grid.Row="1" Grid.Column="1"/>
  6. <TextBlock Text="Age" FontSize="14" Grid.Row="2"/>
  7. <TextBlock Text="{Binding Age}" FontSize="14" Grid.Row="2" Grid.Column="1"/>
  8. <TextBlock Text="Salary" FontSize="14" Grid.Row="3"/>
  9. <TextBlock Text="{Binding Salary}" FontSize="14" Grid.Row="3" Grid.Column="1"/>

You can see I am binding to a known fields FirstName, LastName, etc. If we were using dynamic classes these properties might not have been known during the design time so I couldn’t have bind the way I am binding here. So I cheated just to show how to create a dynamic objects but not the dynamic binding. Lets first try to bind to dynamic object itself and see what happens. To do that, I am going to change the XAML to bind to list of objects, whose properties are not known during design time (even though I am going to create them in code behind).

Code Snippet
  1. <c1:C1FlexGrid ItemsSource="{Binding People}" AutoGenerateColumns="True"/>

I am using ComponentOne FlexGrid to bind to list of Person to the grid. Now the ViewModel code which returns the People

Code Snippet
  1. List<object> _people = new List<object>();
  2.  
  3.         public List<object> People
  4.         {
  5.             get
  6.             {
  7.                 dynamic person = new ExpandoObject();
  8.                 person.FirstName = "Unni";
  9.                 person.LastName = "Nair";
  10.                 person.Age = 20;
  11.                 person.Salary = 10000;
  12.                 //_people.Add(new Person { FirstName = "Unni", LastName = "Nair", Age = 20, Salary = 10000 });
  13.                 _people.Add(person);
  14.                 return _people;
  15.             }
  16.         }

With this code, if you compile and run, you will notice, it will not display any rows. So there is something wrong here. When I search the net, I ran into a forum posting on the same subject. So as per Min-Hong,

“I am afraid, it is beacuse dynamic does not support reflection.

   Thus does not support databinding(in silverlight databinding uses reflection).”

I did couple of searches and hit a Silverlight feature list voting page on Microsoft, where lot of people requested this. It turned out, Silverlight 4 does not support this feature and I am not sure the state of Silverlight 5. But the good news is that, there were couple of work around to this problem. They are

  • Using emit to create a type using TypeBuilder. There are couple of posting on this model.One such example is here. I approached this model to create a sample code which would generate a 1000 rows and 50 columns and it took almost 2.6 seconds.
  • The second approach is using property bag model and using Silverlight’s suppport for indexer for binding. In this model, the same number of cell generation took only 1.4 seconds. So I decided to stick to this model. I am not going to explain, since Xavior’s blog explained it so good.

So lets look at the code which display our Person List in data grid.

We will add a new class called DynamicDataContext as per Xavior explained in his blog

Code Snippet
  1. public class DynamicDataContext : DynamicObject, INotifyPropertyChanged
  2. {
  3.     private readonly IDictionary<string, object> propertyBag = new Dictionary<string, object>();
  4.  
  5.     public event PropertyChangedEventHandler PropertyChanged;
  6.  
  7.     /// <summary>
  8.     /// The indexer is needed to be able to use indexer-syntax in XAML
  9.     /// to data bind to the properties available in the private property bag.
  10.     /// </summary>
  11.     /// <param name="index">The name of the property.</param>
  12.     /// <returns>The value of the property, or null if the property doesn't exist.</returns>
  13.     public object this[string index]
  14.     {
  15.         get
  16.         {
  17.             object result;
  18.             propertyBag.TryGetValue(index, out result);
  19.             return result;
  20.         }
  21.         set
  22.         {
  23.             propertyBag[index] = value;
  24.             RaisePropertyChanged(index);
  25.         }
  26.     }
  27.  
  28.     public override bool TryGetMember(GetMemberBinder binder, out object result)
  29.     {
  30.         return propertyBag.TryGetValue(binder.Name, out result);
  31.     }
  32.  
  33.     public override bool TrySetMember(SetMemberBinder binder, object value)
  34.     {
  35.         propertyBag[binder.Name] = value;
  36.         RaisePropertyChanged(binder.Name);
  37.         return true;
  38.     }
  39.  
  40.     private void RaisePropertyChanged(string propertyName)
  41.     {
  42.         if (PropertyChanged != null)
  43.             PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  44.     }
  45. }

Since the dynamic object does not support reflection, to show all the properties of the dynamic class in the grid, we need do couple of things in XAML and its code behind. First stop XAML

Code Snippet
  1. <c1:C1FlexGrid Name="_flex" ItemsSource="{Binding People}" AutoGenerateColumns="False"/>

We need to make sure we are not auto generating the columns since Silverlight does not know which are the columns we are going to have in grid, we need to manually create it in the code behind and then add it to the grid. So to do that we will mark the auto generate columns to ‘False’.

Before we go into code behind and see how we create the columns, first look at the ViewModel and see the what are we doing there.

First stop we create the list of DynamicDataContext for People property which is bound to the grid as

Code Snippet
  1. List<DynamicDataContext> _people;
  2.  
  3.         public List<DynamicDataContext> People
  4.         {
  5.             get
  6.             {
  7.                 if (_people == null)
  8.                     GenerateDynamicList();
  9.                 return _people;
  10.             }
  11.         }
  12.  
  13.         private void GenerateDynamicList()
  14.         {
  15.             _people = new List<DynamicDataContext>();
  16.             var person = new DynamicDataContext();
  17.             person["FirstName"] = "Unni";
  18.             person["LastName"] = "Nair";
  19.             person["Age"] = 20;
  20.             person["Salary"] = 10000;
  21.             _people.Add(person);
  22.             EventAggregator.Publish(new List<string> { "FirstName", "LastName", "Age", "Salary" });
  23.         }

Line 3-11 we create the People which is what bound to our grid in XAML.

When we generate the person collection, at the end, we publish an event for view to create the associated columns in the grid, by passing all available column names. It is done by publishing an event with list of column names at line 22. This event publishing is Jounce model of passing information between components.

Now lets look at the view code behind.

Code Snippet
  1. [ExportAsView("MainPage", IsShell = true)]
  2.     public partial class MainPage : UserControl, IEventSink<List<string>>, IPartImportsSatisfiedNotification
  3.     {
  4.         public MainPage()
  5.         {
  6.             InitializeComponent();
  7.         }
  8.  
  9.         [Export]
  10.         public ViewModelRoute Binding
  11.         {
  12.             get { return ViewModelRoute.Create("MainViewModel", "MainPage"); }
  13.         }
  14.  
  15.         [Import]
  16.         public IEventAggregator EventAggregator { get; set; }
  17.  
  18.         public void HandleEvent(List<string> publishedEvent)
  19.         {
  20.             foreach (string name in publishedEvent)
  21.             {
  22.                 Column col = new Column();
  23.                 col.Binding = new System.Windows.Data.Binding(string.Format("[{0}]", name));
  24.                 col.Header = name;
  25.                 _flex.Columns.Add(col);
  26.             }
  27.         }
  28.  
  29.         public void OnImportsSatisfied()
  30.         {
  31.             EventAggregator.Subscribe<List<string>>(this);
  32.         }
  33.     }

This is all Jounce here. When view model send the list of string, (don’t write production code like this 🙂 ) the view event sink intercepts and perform Handle Event method. For every element in the list, we create a new column and add it to our grid to display. That’s about it. Now if you would run this, you will get the result like the following

image

Very simple huh? I think Xaviour’s blog was exceptional in explaining the DynamicDataContent and how we use Silverlight 4’s indexer to identify and bind the dynamic columns.

I want to stop here with couple of points.

1. First of all, we need to create all the columns for the gird in the code behind. So once the collection is build you can send an event over to view and build it there. But most of the cases, you will first identify all the columns that are required to build the columns, so before you start building the data collection, you send the information over to View and build the grid columns before hand.

2. I am sure you have noticed the INotifyPropertyChanged interface implementation, that means we can track the data change events.

3. In ‘DynamicDataContext’, all we are tracking is bound object’s value change. We can extent this further to add your Entity Framework’s entity in it so that you can make changes to the underlying entity in the Data Context itself so that you can make use Entity Frame work’s change tracking for back end data update.

4. You can event extend the ‘DynamicDataContext’ to create hierarchical classes and generate tree like grid with ease. I will try to modify the ‘DynamicDataContext’ in the future blog to show this ability.

Advertisements

Creating Popup Dialog using Jounce Region.

It is little trickier to create a Silverlight pop up dialog box using Jounce. Jounce creates view and associate the viewmodel to it for user controls while pop up dialog boxes are derived off of ChildWindow. So you can not just navigate/region to the control. Even if you would ‘new’ up a dialog, you will lose the View Model associated with it from Jounce Frame work, since you are newing the view. If you would new the view, then you need to revert back to old school view mode injection through code behind, if you would take that approach then you are not really using Jounce to create a good MVVM code. To make it short, it is trickier to use Jounce Framework to show your Child Window (in our case we use C1Window – Component One Child Window). But as you can imagine that since I am writing the block, it is possible and surprisingly easy.

One of my colleague found a hack by goggling. Once I get the link, I will put the link up here so that you get the actual implementation by the original author. We modified a little bit to handle our situation,  Here is the solution;

1. Create a normal User Control page and wrap the content in a Canvas, it is important you have canvas, if you use Grid then the user will not able to move the pop up window around. You can only maximize, minimize and close. If you would use Canvas, then you can do all the things you do with Grid but also move the pop up window around. By default make the canvas collapsed.

2. Create a C1Window, name the control.

3. Inside the C1Window, create a ‘ContentControl’ and give a region name. Here is where we are going to place our view.

4. When user want to activate the dialog, make the Canvas visible. Also navigate to the view, which will be exported to region defined in the Content Control.

5. When all the actions are done, close the dialog, navigate back to the calling page, make the Canvas visibility to Collapsed.

I wrote a simple solution to show how it works. Here is the main page XAML, which has a button, when clicked it is suppose to show the pop up dialog.

    <Grid x:Name="LayoutRoot" Background="White"
          d:DataContext="{d:DesignInstance sampleData:DesignMainViewModel, IsDesignTimeCreatable=True}">
        <Grid.Resources>
            <local:Converters x:Key="myConverter"/>
        </Grid.Resources>
        <StackPanel>
        <Button Content="Click me" Command="{Binding ClickMe}"/>
        <Canvas Name="hiddencanvas" Visibility="Collapsed">            
                <c1:C1Window Header="Title" Height="200" Width="200">
                    <i:Interaction.Triggers>
                        <i:EventTrigger EventName="Closing">
                            <i:InvokeCommandAction Command="{Binding ClosingCommand}" CommandParameter="{Binding Converter={StaticResource myConverter}}"/>
                        </i:EventTrigger>
                    </i:Interaction.Triggers>
                    <ContentControl  Region:ExportAsRegion.RegionName="ShowMeRegion"/>
                </c1:C1Window>
            </Canvas>
        </StackPanel>
    </Grid>

 

The button which initiate the pop up dialog bound to the command ClickMe in the ViewModel. For time being ignore the event trigger.

*** Edit on the above code **

Replaced the trigger with behavior as follows

<i:Interaction.Behaviors>
   <local:CloseBehavior/>
</i:Interaction.Behaviors>  

local class which implements close behavior as follow
public class CloseBehavior : Behavior<C1Window>
    {
        public CloseBehavior()
            : base()
        {
        }

        protected override void OnAttached()
        {
            base.OnAttached();
            AssociatedObject.Closing += new CancelEventHandler(AssociatedObject_Closing);
        }

        void AssociatedObject_Closing(object sender, CancelEventArgs e)
        {
            e.Cancel = true;
            Canvas c = AssociatedObject.Parent as Canvas;
            c.Visibility = Visibility.Collapsed;
        }

        protected override void OnDetaching()
        {
            base.OnDetaching();
            AssociatedObject.Closing -= new CancelEventHandler(AssociatedObject_Closing); 
        }

    }

*** End Edit ****

 
[ExportAsViewModel("MainViewModel")]
    public class MainViewModel : BaseViewModel
    {
        public IActionCommand<string> ClickMe { get; set; }
        public IActionCommand<CancelEventArgs> ClosingCommand { get; set; }

        public MainViewModel()
        {
            ClickMe = new ActionCommand<string>(
                view =>
                {
                    EventAggregator.Publish("ShowCanvas");
                    EventAggregator.Publish("ShowMe".AsViewNavigationArgs());
                }
                );

            ClosingCommand = new ActionCommand<CancelEventArgs>(
                view =>
                {
                    view.Cancel = true;
                }
                );
        }

    }

 

If you notice the ClickMe method implementation, it fires two events. First one is called ShowCanvas, which will be intercepted at the code behind to make the canvas visible. The second event is to stage the view you want to show in the view model. Lets look at the code behind and see how it makes the canvas visible.

[ExportAsView("MainPage", IsShell = true)]
    public partial class MainPage : UserControl, IPartImportsSatisfiedNotification, IEventSink<string>
    {
        [Import]
        public IEventAggregator EventAggregator { get; set; }

        public MainPage()
        {
            InitializeComponent();
        }

        [Export]
        public ViewModelRoute Binding
        {
            get { return ViewModelRoute.Create("MainViewModel", "MainPage"); }
        }

        #region IPartImportsSatisfiedNotification Members

        public void OnImportsSatisfied()
        {
            EventAggregator.Subscribe<string>(this);
        }

        #endregion

        #region IEventSink<string> Members

        public void HandleEvent(string publishedEvent)
        {
            if (publishedEvent.Equals("ShowCanvas"))
                hiddencanvas.Visibility = System.Windows.Visibility.Visible;
        }

        #endregion

    }

If you look at the HandleEvent method at the end of the code, you will see, we are checking the incoming message to see if it is ‘ShowCanvas’ then make the canvas visible.

Now lets go back to the second call made from the view model to load the ‘ShowMe’ page. it is important that, here you use User Control, so that Jounce does the wiring for you. The ShowMe.XAMl look like the following, nothing fancy

    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock Text="Hello from Popup Window" FontSize="16"/>
    </Grid>

In the code behind, as you would do to any user control which needed to be hosted in a region, export it to the region when called.

[ExportAsView("ShowMe")]
[ExportViewToRegion("ShowMe", "ShowMeRegion")]
public partial class ShowMe : UserControl
{
    public ShowMe()
    {
        InitializeComponent();
    }
}

 

That’s about it. I added a small twist to the code, by listening to Closing event of the pop up window using Event Trigger. Just an experiment that’s all. You can very well add the Closing event in the code behind and all will be good as well.

Creating Silverlight Navigation using Jounce

Jounce has very good documentation on how to create Navigation and Region Management in the Codeplex. I always starts there. What I am doing to here to illustrate how to create Silverlight Navigation step by step. So before we go any further what are we trying to achieve? Here are the basic requirements;

I. Create two buttons on top of the screen as ‘Hello World’ and ‘Hello World1’ and bottom section will have a panel which display a page based on the button selection.

II. Create two separate pages which will display ‘Hello World’ and ‘Hello World1’. See the subtle difference in the text ‘World1’.

III. When user click the first button ‘Hello World’, the bottom section shows the ‘Hello World’ page and on ‘Hello World1’ click it shows ‘Hello World1’. At any point of time, we should see only one page.

Ok now we have the requirements done, lets step through the process of creating the application.

 

I. Create UI Part.

First lets create a simple Jounce application. I would strongly recommend you to go to Jounce page @ Codeplex and download the Jounce template for Visual Studio 2010. I always use it and it eliminates lot of code deletion and adding reference extra. So We start out by creating a Jounce Application

image

 

Once the project created, I would recommend you build and run it. I always do that just to eliminate any missing references.  If all are good you are suppose to get the following screen with ‘Welcome to Jounce’ message. If you do not see it then, you have a problem with Jounce references. One reason you might not able to get it up and running if you do not have System.Interactivity.dll not in your GAC.

image 

Lets assume that, you got it working. Next we are going to implement the first requirement that to add two buttons and a panel. We modify the MainPage.XAML to achieve this.

1. First add two buttons for Hello World and Hello World 1

        <Button Content="Hello World" Command="{Binding HelloWorld}" Grid.Row="0" Grid.Column="1"/>
        <Button Content="Hello World1" Command="{Binding HelloWorld1}" Grid.Row="0" Grid.Column="2"/>

2. Next we need to create the content panel to host the page on button click

<ContentControl Grid.Row="1" Grid.ColumnSpan="4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
            <ContentControl.Content>
                <StackPanel Orientation="Horizontal"/>
            </ContentControl.Content>
        </ContentControl>

This will create bottom panel to host the pages.

3. We are not done yet in the  main page.  Next we need to name the stack panel as a region to host the pages. This is achieved by adding Jounce Region namespace and then use the Region Name to name the panel.

<UserControl x:Class="NavigationTest.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:sampleData="clr-namespace:NavigationTest.SampleData"
    xmlns:Regions="clr-namespace:Jounce.Regions;assembly=Jounce"
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400">

 

If you notice the 3rd line from the bottom, we are referencing the region namespace which we will use to name the Content Control. We are going to modify the step (2) and add name to content control. So with the change it will look like this.

<ContentControl Grid.Row="1" Grid.ColumnSpan="4" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
                HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch"
                Regions:ExportAsRegion.RegionName="AppRegion">
            <ContentControl.Content>
                <StackPanel Orientation="Horizontal"/>
            </ContentControl.Content>
        </ContentControl>

We named the content control as “AppRegion” that is the 3rd line from the top. That’s it. Now we completed the requirement (1). We created two buttons and a panel with a region name.

 

II. Create Two Pages.

Now lets look at the requirement (2), that is to create two separate pages with just a textblock which displays two different strings. In the solution, now add new Silverlight Page like the following

image

This will create a new page and we add a text block to display “Hello World” like the following

<Grid x:Name="LayoutRoot">
        <TextBlock Text="Hello World"/>
</Grid>

Repeat the same and create HelloWorld1Page.

III. Implement Navigation.

Ok now we have the main page and two addition pages as we wanted, now we need to tie all of them together. So lets start from main page view model. We need to implement the command to execute on button click happens.  Before we start, delete the interface definition for the welcome text since we no longer use that. Now the modified code of View Model look like the following

namespace NavigationTest.ViewModel
{
    using Jounce.Core.Command;
    using Jounce.Framework.Command;
    using Jounce.Core.View;

    [ExportAsViewModel("MainViewModel")]
    public class MainViewModel : BaseViewModel, IMainViewModel
    {
        public IActionCommand<string> HelloWorld { get; private set; }
        public IActionCommand<string> HelloWorld1 { get; private set; }

        public MainViewModel()
        {
            HelloWorld = new ActionCommand<string>(ShowHelloWorld);
            HelloWorld1 = new ActionCommand<string>(ShowHelloWorld1);
        }

        public void ShowHelloWorld(string parameter)
        {
            EventAggregator.Publish(new ViewNavigationArgs("HelloWorld"));
        }
        public void ShowHelloWorld1(string parameter)
        {
            EventAggregator.Publish(new ViewNavigationArgs("HelloWorld1"));
        }
    }
}

We defined two button implementation one for each button. If you see the implementation, all we are doing is that, we are publishing an event with ViewNavigationArgs with the name of the pages in other words, the name you use in ‘ExportAsView’ for each new page you created. If you remember we did not jouncify the two pages we created so it does not have ‘ExportAsView’. So lets do that. Open the code behind for HelloWorld.cs and make the code look like the following

namespace NavigationTest
{
    [ExportAsView("HelloWorld")]
    [ExportViewToRegion("HelloWorld", "AppRegion")]
    public partial class HelloWorldPage : Page
    {
        public HelloWorldPage()
        {
            InitializeComponent();
        }

        // Executes when the user navigates to this page.
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }

    }
}

The third line is the standard Jounce attribute to name the page. The interesting part in this page is the fourth line. What we are saying here is that, when you get control, make sure, you identify the ‘AppRegion’ control and pace the view in there. Will do the same for HellowWorld1 code behind.

 

namespace NavigationTest
{
    [ExportAsView("HelloWorld1")]
    [ExportViewToRegion("HelloWorld1", "AppRegion")]
    public partial class HelloWorld1Page : Page
    {
        public HelloWorld1Page()
        {
            InitializeComponent();
        }

        // Executes when the user navigates to this page.
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }

    }
}

That’s it, now with these changes you would see a screen something like the following

image

Clicking Hello World button will show

image

now clicking Hello World 1 will replace hello world page with Hello World 1 as shown below

image

 

That’s about it. Now if you want to show both the controls then instead of using Content Control in the main page, use ItemsControl. So the bottom line is, have a region defined in the main page to host the pages. When you want to host a page, just publish the ‘ViewNavigationArgs’ with the page name. In the page, decorate the page with which region that page has to display by ‘ExportViewToRegion’. As simple as that. Hopefully it helps out. I will attempt the same in Caliburn next.

Step into Caliburn.Micro World

This is my first attempt at Caliburn so this might be little crude. After some very busy time, I thought I will give it a go on Caliburn.Micro. To my surprise ‘Hello World’ was not that complicated as I thought it would be. So in this blog, we are going to look at writing simple Hello World program to understand the following

I. What are all the things required to build an application.

II. MVVM.

III. Simple data binding.

IV. Design time data or Blendability.

V. Distribution file size.

To create a simple application, I followed this introduction link and got the Hello World working in no time. The steps are simple.

1. Create a brand new silverlight application.

2. If you do not have NuGet please go get it, with NuGet in place. Go to Tools->Library Package Manager –> Manage NuGet Packages and install Caliburn.Micro.

Once you install, not only it brings down the required dll, but also it creates the shell template with View, ViewModel and interface for the view model.

3. Follow the steps in the links mentioned to clean up App.XAML and make sure you delete the MainPage.XAML and run the program. You will see Hello World.

4. In this process we really did not use ViewModel. If you look at the ShellViewModel.cs, there is no code. Lets modify the code little bit to have small taste of MVVM.

5. Go to ShellView.XAML and change the textblock as follows;

<TextBlock Name="HelloWorld"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center"
                   FontSize="20" />

What we did here is that, instead of passing the constant now we named the TextBlock so that it can get some data from view model.

6. Go to IShell.cs and add the following

public interface IShell 
    {
        string HelloWorld { get; }
    }

Same as Jounce, I am creating the variable in here so that I can use it for design time data.

7. Modify the SheViewModel.cs as follows

[Export(typeof(IShell))]
    public class ShellViewModel : IShell 
    {
        #region IShell Members

        public string HelloWorld
        {
            get { return "Hello Unni"; }
        }

        #endregion
    }

 

8. Now if you run the code, it will show ‘Hello Unni’ instead of hello word from Caliburn. We will look at how binding happened in a second.

 

In this process you deleted lot of code and added few lines.

I. What are all the things required to build an application.

With our first program running, lets look at the components required to write Silverlight using Caliburn. You need two dlls, the first one, of course is Calburn.Micro.dll and the second one is System.Interactivity.dll. If you use blend then this dll will be available in GAC for you, you need to add the reference to your solution.

II. MVVM.

Caliurn uses simple convention to identify View and ViewModels, it is pretty cool. All your view have to end with ‘View’ and the view model as you guessed it, it should end with ‘ViewModel’, thats about it. So in the ’HelloWorld’, our main View is Shell and is called ‘ShellView’ and its corresponding view model is ‘ShellViewModel’. but if you would look at the app.xaml.cs we did not say which one is our starting page. It is done in the bootstrapper. If you look at the class definition of bootstrapper

public class AppBootstrapper : Bootstrapper<IShell>

 

So if you want to specify a different page, all you have to do is to bootstrap off of its view mode.

III. Simple data binding.

Data Binding is super simple. In our Hello word program the TextBlock name was ‘HelloWorld’ and if you look at the view model, we have a property called ‘HelloWord’. So binding is done through Name in XAML and associated property in the view model.

IV. Design time data or Blendability.

Unfortunately, so far I am not successful in enabling design time data. Here is what I attempted. Created a new class called SampleShellViewModel.cs as follows

namespace HelloWorld
{
    public class SampleShellViewModel:IShell
    {

        #region IShell Members

        public string HelloWorld
        {
            get { return "Hello World"; }
        }

        #endregion
    }
}

Modified the ShellView.XAML as follows

<UserControl x:Class="HelloWorld.ShellView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
             mc:Ignorable="d"
             xmlns:sampleData="clr-namespace:HelloWorld"
             d:DesignHeight="287" d:DesignWidth="518"
             >

    <Grid Background="White" d:DataContext="{d:DesignInstance sampleData:SampleShellViewModel, IsDesignTimeCreatable=True}">
        <TextBlock Name="HelloWorld"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center"
                   FontSize="20" />
    </Grid>

</UserControl>

But view does not recognizes the design time data object. I will continue work on it and see what am I doing wrong here and update the post once I find the answer.

** By default Caliburn Micro naming convention will not work with design time data. So instead of using Name=”Hello World”, do Content=”{Binding HelloWorld"}” will do run time binding and design time data binding.”

V. Distribution file size.

The distribution dll for Caliburn is only 41K compressed.

 

This is my baby steps into Caliburn and so far what I found is that it is easy to use.

Comparing to Jounce, here are some of my observations;

1. Compare to Jounce the distribution dll, Caliburn is only 6K more, it is not a big deal.

2. Caliburn uses convention to do data binding and View, View Model binding while in Jounce, for every view, you have to write the ViewModelRoute binding.

3. Jounce is attribute based development, while Caliburn is convention based development.

4. Since I do not have definite answer on Blendability, I am not going to comment on it yet.

4. By default the convention binding will not work on Blendabilty. If you want design time data, add or replace Name with normal Binding.

5. You have to have a bootstrapper for Caliburn, while Jounce it is build in.

6. Caliburn can use any IoC container, while Jounce is build on top of MEF.

I will go more about binding, MEF and other features in a later blog.

Design time data – Second look

In my previous blog I went through how Jounce template for Silverlight application creates default application and generates plumbing in place to use Design Time data. All the projects I have worked on, we completely ignore it. For the last couple of months, I have been consciously taking extra steps to use Design Time data. As I mentioned in my multiple posts, it is simply of the best feature most of every one ignores. Without doubt, in my opinion it is one of the easiest one to achieve without lot of learning curve and available out of the box. Jounce Silverlight Application template already creates all interfaces and implementation in place to use it. In my previous post I went though what is available out of the box. In this blog, I am going to take it one extra step.

I need to emphasis here, this would be lot more easier if we would use Expression Blend. Since we are not designers, we are going to look at solving the problem traditional way as a coder.

Here are the requirements for the application.

1. It has to display the data in grid format.

2. The column order has to be Name, Age, Salary and Sex.

3. Salary has to currency formatted and should be right aligned.

4. In case the record allows ‘IsEnable’ then change the background color of the salary field to be RED.

First we are going to create a Silverlight application using Jounce Silverlight Application framework. What I am going to do is to crate a grid, which will show our favorite Person class information. So here is our person class.

public class Person : INotifyPropertyChanged
    {
        public string Name { get; set; }
        public int Salary { get; set; }
        public char Sex { get; set; }
        public int Age { get; set; }
        public bool IsEnabled { get; set; }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(string info)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(info));
            }
        }
    }

Normally the way, I go about doing is, to crank up the XAML and run the application and then see if the grid shows my data properly if not tweak the XAML, rinse and repeat the process till you get what you want. In my opinion we are wasting time on this, where all the requirement in this case can be verified in the IDE itself. Lets see how it should have been done (IMHO).

Since we have created the Silverlight application using Jounce Template, it already created the interface for data layer. I removed the default string variable to List of Person, like the following in the IMainViewModel.cs

using System.Collections.Generic;
namespace FilteringIssueOnCellTemplate.Common
{
    public interface IMainViewModel
    {
        List<Person> People { get; }
    }
}

Just a refresher here, if you look at the solution, we are after ‘DesignMainViewModel.cs’ under SampleData. This particular class will be used for design time data. We will see later how it is hooked up for design time data. For now, lets change this class to return bunch of dummy data which covers our requirement.

using System;
using FilteringIssueOnCellTemplate.Common;
using System.Collections.Generic;

namespace FilteringIssueOnCellTemplate.SampleData
{
    public class DesignMainViewModel : IMainViewModel
    {
        public List<Person> People
        {
            get
            {
                List<Person> _ppl = new List<Person>();
                _ppl.Add(new Person() { Age = 20, Name = "A", Salary = 10000, Sex = 'F', IsEnabled = true });
                _ppl.Add(new Person() { Age = 20, Name = "B", Salary = 10000, Sex = 'M', IsEnabled = false });
                _ppl.Add(new Person() { Age = 20, Name = "C", Salary = 10000, Sex = 'F', IsEnabled = false });
                _ppl.Add(new Person() { Age = 20, Name = "D", Salary = 10000, Sex = 'F', IsEnabled = true });
                _ppl.Add(new Person() { Age = 20, Name = "E", Salary = 10000, Sex = 'M', IsEnabled = false });
                _ppl.Add(new Person() { Age = 20, Name = "F", Salary = 10000, Sex = 'M', IsEnabled = true });
                return _ppl;
            }
        }
    }
}

As you can see, I have few of the records set to IsEnabled to True so we can see if the XAML I wrote really works.

<Grid x:Name="LayoutRoot" Background="White"
          d:DataContext="{d:DesignInstance sampleData:DesignMainViewModel, IsDesignTimeCreatable=True}">
</Grid>

By default the layout grid looks like this. If you notice, the second line, where d:DataContext is set to our sample view model. So Lets put our data grid control in there and see how it looks. So I am going to add my grid and bind it to Person collection ‘People’ like the following

<c1:C1FlexGrid ItemsSource="{Binding People}"/>

Now if you see the design screen after adding the line would like the following

image 

So we need to change the column order and display only required fields. So I modify the XAML like the following

<c1:C1FlexGrid ItemsSource="{Binding People}">
            <c1:C1FlexGrid.Columns>
                <c1:Column Binding="{Binding Name, Mode=TwoWay}"/>
                <c1:Column Binding="{Binding Age, Mode=TwoWay}"/>
                <c1:Column Binding="{Binding Salary, Mode=TwoWay}"/>
                <c1:Column Binding="{Binding Sex, Mode=TwoWay}"/>
            </c1:C1FlexGrid.Columns>
        </c1:C1FlexGrid>

If you are like the normal developer here you would compile and run to see how it looks, I say ‘stop’ and look at the design panel

image 

You might have noticed, Name field appears twice so we have a bug in the XAML.  It is easy, by default, data grid AutoGenerateColumn is True so we change it to False. Now after adding and look at the design Panel, the duplicate column is gone.

image

Now we are going to tweak the XAML to add additional requirements. lets look at the simple ones, Need to change the formatting of the column to currency and right aligned. Modify the salary column to the following

<c1:Column Binding="{Binding Salary, Mode=TwoWay, StringFormat=c}" HorizontalAlignment="Right"/>

 

The interesting part here is that, as you change you can see design panel changes. With the above changes, now you got the gird to look almost close to what you want except the back ground color.

image

Now we need to set the back ground color of the salary, you can not do dynamic binding to back ground for a column, only way you can do that is through the cell template.

Before I write cell template, I am going to write a converter which will check and see if IsEnabled is set to true or false like the following

public class ColorConverterForRowType : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            bool item = (bool)value;

            if (item == false)
                return new SolidColorBrush(Color.FromArgb(255, 0xde, 0xe2, 0xe6));

            return new SolidColorBrush(Colors.Red);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return null;
        }
    }

Now add the cell template in the XAML as follows

 

<c1:Column Binding="{Binding Salary, Mode=TwoWay, StringFormat=c}" HorizontalAlignment="Right">
                    <c1:Column.CellTemplate>
                        <DataTemplate>
                            <Grid>
                                <Border Background="{Binding IsEnabled, Converter={StaticResource ColorConverterForRowType}}"/>
                                <TextBlock Text="{Binding Salary, Mode=TwoWay, StringFormat=c}" HorizontalAlignment="Right"/>
                            </Grid>
                        </DataTemplate>
                    </c1:Column.CellTemplate>
                </c1:Column>

Now just compile the code and see what is in the panel

image

Look at it, we did not run once and we got the look and feel the initial requirement. It is very easy and avoid all those multi runs to see if the screen looks like we need.

It works in my computer (Starting problems – Jounce)

I was out on a vaccation and happy to be back. I will post couple of pictures later.

Now to the fun part, Couple of my friends have a problem developing ‘Hello World’ program using Jounce. Now that Jounce 1.0 is out, it is no longer required to download the source code to build and generate the dll to use. You can now download the single Jounce.dll directly from download page or using NuGet get the Jounce Package. So my friends tried the first approach by using the single Jounce.dll. The program compiles just fine but when you run the program, it fails at runtime. But I could create ‘Hello World’ program all day and it does not fail at run time. By the way, I followed the same steps by friends did. As all the programmers say, ‘It works on my PC’ 🙂

I always like good debugging. So I sat with one of my friend and see what is happening. For starters, when you create Jounce application, you end up deleting all the code from App.XAML.cs since application startup will be taken over by Jounce Framework. Since there are no code in App.XAML.cs, the trapping error was little difficult. So I went in and put the code the catch the unhandled exception in App.XAML.cs. With that armed, put a break point inside the unhandled exception code, when I looked at the error log, I could see, it is looking for ‘System.Windows.Interactivity.dll’ and that was not in the reference folder. We added the missing dll and there it is, ‘Hello World’.

Now the question, how come it worked in my box not on my friends, we both did the same things. The only difference was, I have Expression Blend installed and this dll is available in GAC to find it. So the bottom line, is if you are using Jounce and do not have Expression Blend installed, make sure you have this dll in your reference other wise you will run into the same problem. You will need this dll if you are going to use MVVMLite or Caliburn.Micro as well.

There is still an outstanding issue with NuGet, with out Expression Blend install, Nuget install for Jounce is failing. I haven’t got ten around to see why is it failing. I will update this post once I get an answer.

** Update – “I looks like maybe one of the Expression SDK because of the Navigation Trigger. Will see if I can add the dep to pkg” from our good friend Jeremy. **

Hope this helps someone.

MVVM Frameworks Compare and Contrast – 1

This subject will never be accurate, regardless I am going to take a stab at it. The question is, if it is not going to accurate why do it? Well, first to educate myself with all available framework. I am sure by looking at different framework, learn some neat stuff on coding and patterns. One last thing, by putting it out in it blog if I am wrong, I will know and correct myself. One last point, some of the items become out-of-date soon so I will be very clear on which version and build I am using as I do this blog.

Before I go any further, I would love to hear from you, which framework are you using and if you could explain why you choose that will help me a lot.

Couple of things I need to tell upfront;

  1. This is purely for Silverlight, sorry no WPF or WP7.
  2. I have been using Jounce for a while and I love it. So I might have bias towards Jounce so if you see it please correct me.
  3. I might not cover all the features in all the frame works, so if you think I might have missed something, please let me know.

Now for the MVVM Framework comparison, I am going to use the follow common frameworks available.

I am thinking of covering following subject on each of the frameworks. If you can think of some feature I need to add here, please let me know as well.

  • Documentation and samples.
  • Simple Hello World
  • Event Aggregation
  • Commanding
  • Region Management
  • Navigation
  • Working with Multiple XAP files.
  • Design Time data and Blentability.
  • and more