Now that we have our mock data showing up in Expression Blend, let’s get it working under Cider (the VS 2008 WPF designer). If you are really lucky, you might have hit all the right notes necessary to get it working the first time. If you fall under the other 99%, then follow the tips below:
Cider does not like the Window control for design-time data binding…
That’s right. This one actually took me the longest to figure out. It only hit me because I had one UserControl working correctly, so I started with a stripped down Window to determine the root cause. Turns out, if I change the Window to a UserControl, Cider is happy to do the data binding. So there are two ways you could get around this limitation:
- Create an intermediate UserControl, and host that inside your Window; or
- Add the DataContext to the root container element in your Window (e.g. a Grid). That seems to sidestep the Window data binding problem.
Put UserControl.DataContext after UserControl.Resources! … And, declare the serviceProvider on the UserControl.Resources too!
I was getting erratic behavior hosting different controls from within the same project in my main Window. It ended up originating from a missing serviceProvider declaration. The hosted control is not able to find my App.xaml declarations, apparently. Therefore, if you host your UserControl Foo inside Control Bar, the designer will cough out the error "Could not create an instance of type ‘Foo" when you open Bar in the designer. Fortunately, you are able to define it in both App.xaml and on the UserControl, and it will not create problems in both Cider or Blend.
Sometimes, Cider calls IValueConverters with strange data
I have had Cider call a ValueConverter with a string, when I was expecting a business object instance. This caused the designer to catch an exception. The solution was to ignore unexpected types when in design mode (and this is actually suggested in a Microsoft Cide blog). Easy enough.
Now, for the final step…
Even though the previous steps should get the mock data showing up in Cider as well, you still have a problem: the design data will show up at run-time as well. There is an easy way to fix this:
public TeamMemberDataUserControl()
{
InitializeComponent();
if (!DesignerProperties.GetIsInDesignMode(this))
{
// Clear the design time data context
ClearValue(DataContextProperty);
}
}
You just clear the DataContext in the constructor of your control. That will execute at run-time, and reset the DataContext as if the XAML declaration wasn’t there.
As Eduardo pointed out to me, this has the side benefit of fixing another issue, as you will see in a bit. There are two different situations where you can see a control in design-mode. The simplest one is when you open the control file (let’s call it A.xaml) directly. The other one is when you open a control (B.xaml) which hosts A.xaml. In the latter situation, the designer will pass in the DataContext to the hosted control, but only if it does not already have a DataContext assigned already. Clearing the DataContext property in the constructor seems to do the trick. Eduardo also worked in a cleaner solution using attached properties, so he might blog a bit about that approach.
Wrap up
By following the steps in these two posts, you should be able to get your application showing design time data both in Expression Blend and Cider. You should not only be able to get that data in simple UserControls, but also Windows that nest other UserControls. If you would like to see the source code for an application that puts this into practice, take a look at the Scrum Sprint Monitor source code at CodePlex. Hope this is useful to you!
Recent Comments