Last week I was impressed by Paul Stovell’s marvelous project – MicroModels. In a nutshell a micro model is a view model over your objects, which allow you to define dynamic properties, collection and commands. You can read more about it in Paul’s introductory blog post here.
Despite its great features, “MicroModels” has one big limitation - it does not run in Silverlight. And this is where my journey began. My mission was to port the code to Silverlight with little to no modifications.
The task was not an easy one, but after a lot of head scratching and hair pulling I was able to complete it. It involved replacing the TypeDescriptor’s logic with dynamic type generation, partially evaluating local closures in compiler generated expression trees and other tricks typically developers don’t do in a normal working day. Despite all these hurdles, the good news is that the code is working fine in Silverlight and everything is supported.
The way the framework is used in Silverlight is almost the same as it is in WPF. You define your MicroModel with exactly the same way using your already familiar methods:
public class EditCustomerModel : MicroModel
{
public EditCustomerModel(Customer customer, CustomerRepository customerRepository)
{
Property(() => customer.FirstName);
Property(() => customer.LastName).Named("Surname");
Property("FullName", () => string.Format("{0} {1}", customer.FirstName, customer.LastName));
Command("Save", () => customerRepository.Save(customer));
}
}
The only thing that you have to change is in the XAML. You will have to data bind your root DataContext to a new property of the MicroModel, instead of the model itself. The property is called Object. Here is the respective XAML for the EditCustomerModel:
<Grid DataContext="{Binding Object}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition />
</Grid.RowDefinitions>
<Button Content="Save" prism:Click.Command="{Binding Path=Save}"/>
<Border Background="#f0f0f0" Grid.Row="1">
<StackPanel>
<StackPanel Orientation="Horizontal" Margin="1">
<TextBlock Margin="1" Width="130">FirstName</TextBlock>
<TextBox Margin="1" Width="50" Text="{Binding Path=FirstName, Mode=TwoWay}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="1">
<TextBlock Margin="1" Width="130">Surname</TextBlock>
<TextBox Margin="1" Width="200" Text="{Binding Path=Surname, Mode=TwoWay}" />
</StackPanel>
<StackPanel Orientation="Horizontal" Margin="1">
<TextBlock Margin="1" Width="130">Full Name</TextBlock>
<TextBlock Margin="1" Width="200" Height="50" Text="{Binding Path=FullName}" />
</StackPanel>
</StackPanel>
</Border>
</Grid>
The same rule with binding to the Object applies to the Collection properties. Here is another XAML snippet, which illustrates the use of an ItemsControl bound to a collection property of the micro model:
<ItemsControl Grid.Row="1" ItemsSource="{Binding Path=LineItems}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid DataContext="{Binding Object}" >
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
<ColumnDefinition Width="80" />
</Grid.ColumnDefinitions>
<TextBox Margin="1" Grid.Column="0" Text="{Binding Path=ProductName, Mode=TwoWay}" />
<TextBlock Margin="3" Grid.Column="1" Text="{Binding Path=UnitPrice}" />
<TextBox Margin="1" Grid.Column="2" Text="{Binding Path=Quantity, Mode=TwoWay}" />
<TextBlock Margin="3" Grid.Column="3" Text="{Binding Path=LineTotal}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I have ported the sample project in the Paul’s source code so you can play with them as well. I have tried to reuse as much code as possible and almost everything except the XAML files is shared between WPF and Silverlight. Actually you can play with the example right here:
You can download the binaries here.
Have fun micro-modeling in Silverlight.