Wednesday, 26 November 2008


To make UI design easier in Blend we want to provide dummy data at design time. Using an ObjectDataProvider with an ObjectType attribute achieves this (provided the bound datasource can provide dummy data).

<ObjectDataProvider x:Key="DesignTimeDataProvider" d:IsDataSource="True" ObjectType="{x:Type Dummy_Application:PeopleDataProvider}"/>
However it is not possible to replace the ObjectType with an ObjectInstance at runtime.
We got round that problem by using two ObjectDataProviders:
<ObjectDataProvider x:Key="DesignTimeDataProvider" d:IsDataSource="True" ObjectType="{x:Type Dummy_Application:PeopleDataProvider}"/>
<ObjectDataProvider x:Key="InnerDataProvider" d:IsDataSource="true" ObjectInstance="{StaticResource DesignTimeDataProvider}"/>
<ListBox ItemsSource="{Binding Path=DataProvider.PeopleList, Source={StaticResource InnerDataProvider}}"/>
Then in the code behind we replace the ObjectInstance with our freshly minted data source:
ObjectDataProvider odpWindow = (ObjectDataProvider)this.FindResource("InnerDataProvider");
odpWindow.ObjectInstance= newPeopleDataProvider;
The problem with this approach is that at runtime a datasource is created (as part of InitializeComponent) that is then immediately discarded.

To resolve this I created my own ObjectDataProvider which nulls the ObjectType at runtime. This is enough to allow the ODP to accept a change to the ObjectInstance without complaint.
public class MyObjectDataProvider : ObjectDataProvider
bool isInDesignMode = (bool)DesignerProperties.IsInDesignModeProperty.GetMetadata(typeof(DependencyObject)).DefaultValue;
public new Type ObjectType
get { return base.ObjectType; }
if (!isInDesignMode) value = null;
base.ObjectType = value;

public partial class PersonEditView : Window
public PersonEditView()
((ObjectDataProvider)this.FindResource("DataModel")).ObjectInstance = model; }
The xaml then becomes simpler and cleaner:
<local:MyObjectDataProvider x:Key="DataModel" d:IsDataSource="True" ObjectType="{x:Type local:PersonEditModel}" />
<TextBlock Text="{Binding Source={StaticResource DataModel}, Path=APerson.Surname}"/>

No comments: