Design-time data in WPF with d:DesignInstance
When you build WPF Views with the MVVM pattern, the real DataContext is usually assigned at runtime (e.g. through dependency injection or a DataTemplate). That is great for the running application, but the Visual Studio / Blend XAML designer has no idea what type sits behind your bindings. The result is an empty, lifeless design surface and no IntelliSense for your {Binding} paths.
This tutorial shows how to feed the designer with design-time data using d:DataContext and {d:DesignInstance}, so you get a populated preview and full binding IntelliSense β without affecting the runtime behaviour of your app.
The goal
We want to add a single line to a View that does two things:
- Tell the designer which ViewModel type the View binds to (IntelliSense for binding paths).
- Show realistic sample data on the design surface (text, list items, states, etc.).
The end result looks like this:
1
2
3
4
5
6
7
8
9
10
11
<Window x:Class="YOURAPP.Views.MainWindow"
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:dt="clr-namespace:YOURAPP.DesignTime"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=dt:DesignMainWindowViewModel, IsDesignTimeCreatable=True}"
Title="MainWindow" Height="450" Width="800">
...
</Window>
How it works: the d: namespace and mc:Ignorable
Two XML namespaces are key here:
1
2
3
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
- The
d:prefix is the design namespace. Anything prefixed withd:only exists for the XAML designer. mc:Ignorable="d"tells the XAML parser (and the runtime) that thed:prefixed attributes can be safely ignored when the app actually runs.
That is the whole trick: d:DataContext overrides the design surface only, while the real DataContext is still set at runtime. The two never collide.
| Attribute | Active at design time | Active at runtime |
|---|---|---|
DataContext |
β (usually unset) | β |
d:DataContext |
β | β (ignored) |
{d:DesignInstance} explained
{d:DesignInstance} is a markup extension that creates (or fakes) an instance of a type for the designer:
1
d:DataContext="{d:DesignInstance Type=dt:DesignMainWindowViewModel, IsDesignTimeCreatable=True}"
Typeβ the type the designer should treat as theDataContext. The designer reads its public properties to provide binding IntelliSense.IsDesignTimeCreatableβ controls how the designer obtains the data:Trueβ the designer actually instantiates the type (calls its parameterless constructor) and shows the real values your design-time ViewModel exposes. Use this when you want to see sample data.False(default) β the designer does not create an instance. It only inspects the typeβs shape for IntelliSense and shows empty placeholders. Use this when you just want binding autocompletion.
For a populated preview you almost always want IsDesignTimeCreatable=True together with a dedicated design-time ViewModel.
Step-by-step tutorial
Step 1 β Create a DesignTime folder/namespace
Keep your design-time helpers separate from production code. Create a folder DesignTime in your project so the namespace becomes YOURAPP.DesignTime:
1
2
3
4
5
6
7
YOURAPP/
βββ ViewModels/
β βββ MainWindowViewModel.cs
βββ DesignTime/
β βββ DesignMainWindowViewModel.cs
βββ Views/
βββ MainWindow.xaml
Step 2 β The real ViewModel
This is your normal, runtime ViewModel. It typically needs services injected through its constructor:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
namespace YOURAPP.ViewModels
{
public class MainWindowViewModel : ObservableObject
{
private readonly IUserService userService;
public MainWindowViewModel(IUserService userService)
{
this.userService = userService;
Users = new ObservableCollection<UserItem>(userService.GetUsers());
}
public string Title { get; set; }
public ObservableCollection<UserItem> Users { get; }
public bool IsBusy { get; set; }
}
}
Because this constructor takes an IUserService, the designer cannot create it directly β which is exactly why we add a design-time variant.
Step 3 β The design-time ViewModel
Create a ViewModel that inherits from (or mirrors) the real one and has a parameterless constructor filled with believable sample data:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
using System.Collections.ObjectModel;
using YOURAPP.ViewModels;
namespace YOURAPP.DesignTime
{
/// <summary>
/// Design-time only ViewModel that provides sample data for the XAML designer.
/// It is never used at runtime.
/// </summary>
public class DesignMainWindowViewModel : MainWindowViewModel
{
public DesignMainWindowViewModel()
: base(new DesignUserService())
{
Title = "Design-time preview";
IsBusy = false;
Users.Clear();
Users.Add(new UserItem { Name = "Ada Lovelace", Role = "Admin" });
Users.Add(new UserItem { Name = "Alan Turing", Role = "User" });
Users.Add(new UserItem { Name = "Grace Hopper", Role = "Editor" });
}
}
}
Tip: If inheriting is awkward (e.g. the base constructor does heavy work), you can instead create a standalone design ViewModel that simply exposes the same public properties the View binds to. The designer only cares about matching property names and types.
If your real ViewModel needs a service, provide a tiny fake for design time:
1
2
3
4
5
6
7
namespace YOURAPP.DesignTime
{
internal class DesignUserService : IUserService
{
public IEnumerable<UserItem> GetUsers() => Array.Empty<UserItem>();
}
}
Step 4 β Wire it up in the View
Add the dt namespace and the d:DataContext to your Window (or UserControl):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<Window x:Class="YOURAPP.Views.MainWindow"
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:dt="clr-namespace:YOURAPP.DesignTime"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance Type=dt:DesignMainWindowViewModel, IsDesignTimeCreatable=True}"
Title="MainWindow" Height="450" Width="800">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0"
FontSize="20"
Text="{Binding Title}" />
<DataGrid Grid.Row="1"
Margin="0,10,0,0"
ItemsSource="{Binding Users}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Header="Name" Binding="{Binding Name}" />
<DataGridTextColumn Header="Role" Binding="{Binding Role}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
As soon as you build the project, the designer instantiates DesignMainWindowViewModel and the DataGrid shows Ada Lovelace, Alan Turing and Grace Hopper β all without running the app.
Step 5 β Keep the runtime DataContext separate
The real DataContext is still assigned at runtime, e.g. in code-behind or via a DI container:
1
2
3
4
5
6
7
8
public partial class MainWindow : Window
{
public MainWindow(MainWindowViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel; // runtime DataContext
}
}
Because d:DataContext is ignored at runtime (mc:Ignorable="d"), there is no conflict between the design-time and runtime contexts.
Design-time-only data inside the View
Besides the whole DataContext, you can also set individual design-time values with d: prefixed properties. These are handy for previewing a single element:
1
2
3
4
5
<!-- Shows "Sample title" only in the designer -->
<TextBlock Text="{Binding Title}" d:Text="Sample title" />
<!-- Preview list items without a design ViewModel -->
<ListBox d:ItemsSource="{d:SampleData ItemCount=5}" />
d:Text, d:Visibility, d:IsEnabled, etc. all override the runtime value on the design surface only.
Benefits
- Visual feedback while you design β see realistic content (lists, text, states) instead of an empty layout, so spacing, column widths and templates can be judged immediately.
- Binding IntelliSense β typing
{Binding ...}offers the properties of the design type, which reduces typos and broken bindings. - Catch binding errors early β a misspelled property is visible in the designer instead of only showing up as a silent runtime binding failure.
- No runtime impact β everything lives behind the
d:namespace and is stripped out bymc:Ignorable="d". No extra code runs, no extra memory is used in production. - Designer-friendly even with DI β your real ViewModel can require constructor-injected services; the design ViewModel provides a parameterless, data-filled alternative.
- Works in Blend and Visual Studio β both use the same
d:design namespace.
Common pitfalls
| Problem | Cause / Fix |
|---|---|
| Designer shows nothing | You set IsDesignTimeCreatable=True but the design type has no parameterless constructor, or its constructor throws. Add a safe parameterless constructor. |
dt namespace not found |
The clr-namespace:YOURAPP.DesignTime value must match the actual namespace, and the type must be in the same assembly (otherwise add ;assembly=YourAssembly). |
| Sample data appears at runtime | You used DataContext instead of d:DataContext, or forgot mc:Ignorable="d". |
| IntelliSense works but no data | You used IsDesignTimeCreatable=False (or omitted it). Set it to True for a created instance. |
| Changes not visible | Rebuild the project β the designer needs a compiled assembly to instantiate the design ViewModel. |
Summary
Design-time data lets you develop WPF Views with a populated, IntelliSense-aware designer while keeping the runtime DataContext completely separate:
- Add the
d:andmc:namespaces andmc:Ignorable="d". - Create a
YOURAPP.DesignTimenamespace with a parameterless design ViewModel full of sample data. - Point the View at it with
d:DataContext="{d:DesignInstance Type=dt:DesignMainWindowViewModel, IsDesignTimeCreatable=True}". - Assign the real ViewModel at runtime as usual.
The d: namespace guarantees all of this is design-time only β your shipping application stays untouched.