I have a view model which contains an array of items:
public class FooViewModel
{
public FooListItem[] ListItems { get; set; }
...
}
I have created a subclass to act as a design time mock, with dummy data.
public class FooViewModelMock : FooViewModel
{
public FooViewModelMock()
{
ListItems = <test data population...>
...
}
}
I then hook up the mock data in the window, which works fine.
<Window xmlns:mocks="clr-namespace:FooNS.Mocks"
xmlns:models="clr-namespace:FooNS.Model"
d:DataContext="{d:DesignInstance Type=mocks:FooViewModelMock, IsDesignTimeCreatable=True}"> ...
Then within the window I have a DataGrid and bind the ItemsSource to the property on the view model:
<DataGrid ItemsSource="{Binding ListItems}"> ...
The test data shows in the design window fine, but the trouble is that the data context of the DataGrid is still FooViewModelMock, not FooListItem, so I lose intellisense and get messages like "Cannot resolve property 'xxx' in data context of type 'FooViewModelMock'".
I could of course set the data context in the DataGrid:
d:DataContext="{d:DesignInstance models:FooListItem}"
This gets me my intellisense back, but I lose the mock data.
Is there a way I can get the design time data context to propagate down through the ItemsSource binding, and keep both the intellisense and the design view data?
Thanks
To the best of my knowledge, that's a flaw in Visual Studio. Here's how I work around it.
First of all, I don't use DesignInstance as I cannot get it to work in Visual Studio 2013. Instead I use this:
d:DataContext="{x:Static userControls:[ insert class name here ]DesignerData.Example}"
Example is a static property that creates an instance of the ...DesignerData class. I have no idea why this works, but DesignInstance, which should do the exact same thing, doesn't. I've tried to specify IsDesignTimeCreatable but that didn't help.
This class will have to have the required collection property, which in my case returns just data in the form of anonymously typed objects:
public IEnumerable<object> Elements
{
get
{
return new object[]
{
new { ... },
new { ... },
new { ... }
};
}
}
In my case the Elements normally cannot easily be created without the rest of the application running, so using anonymously typed objects like this avoids a whole lot of code in the Elements to let them behave differently at design time.
Due to the flaw in Visual Studio, we'll also have to have the properties of the elements:
public string Key { get; private set; }
public Element Value { get; private set; }
Note however that this is just to avoid warnings and for autocomplete. These will never be actually read.
A big potential downside of this approach is that it cannot be used if the elements of one collection have a property with the same name but with different type as those in another collection.
It's also clumsy and inconvenient, as workarounds are wont to be.