What approaches are available to dummy design-time data in WPF?
Asked Answered
C

8

101

I am working without expression blend and just using the XAML editor in vs2010. The wisdom of this aside, I am increasingly seeing a need for design-time data binding. For simple cases, the FallbackValue property works very nicely (Textboxes and TextBlocks, etc). But especially when dealing with ItemsControl and the like, one really needs sample data to be visible in the designer so that you can adjust and tweak controls and data templates without having to run the executable.

I know that ObjectDataProvider allows for binding to a type, and thus can provide design-time data for visualizing, but then there is some juggling to allow for the real, run-time data to bind without wasting resources by loading loading both the design time, dummied data and the runtime bindings.

Really what I am wanting is the ability to have, say, "John", "Paul", "George", and "Ringo" show up in the XAML designer as stylable items in my ItemsControl, but have real data show up when the application runs.

I also know that Blend allows for some fancy attributes that define design time binding data that are effectively ignored by WPF in run-time conditions.

So my questions are:

1. How might I leverage design-time bindings of collections and non-trivial data in the visual studio XAML designer and then swap to runtime bindings smoothly?

2. How have others solved this design-time vs. runtime data problem? In my case, i cannot very easily use the same data for both (as one would be able to with, say, a database query).

3. Are their alternatives to expression blend that i could use for data-integrated XAML design? (I know there are some alternatives, but I specifically want something I can use and see bound sample data, etc?)

Crake answered 11/12, 2009 at 18:25 Comment(0)
I
121

Using VS2010 you can use Design-Time attributes (works for both SL and WPF). I usually have a mock data-source anyway so it's just a matter of:

  • Adding the namespace declaration

    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    
  • Adding the mock data context to window/control resources

    <UserControl.Resources>
      <ViewModels:MockXViewModel x:Key="DesignViewModel"/>
    </UserControl.Resources>
    
  • Setting design-time data context

    <Grid d:DataContext="{Binding Source={StaticResource DesignViewModel}}" ...
    

Works well enough.

Infare answered 20/3, 2011 at 12:28 Comment(8)
Yep. I think this is the new and clear winner. The other stuff was workarounds, this is more "officially supported"Crake
If you are having problems using d:DataContext you may find some help in this question: #8304303Dubious
Wouldn't this example cause an instance of MockXViewModel to be loaded into your resources for a release build? Is this not a concern?Siddra
FYI: You also need the following, or the VS2012 compiler won't compile the xaml file: xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" and mc:Ignorable="d"Ingres
jpierson is right. I prefer to use <Grid d:DataContext="{d:DesignInstance Type=ViewModels:MockXViewModel, IsDesignTimeCreatable=True}" .... This way, the mocked viewmodel will only be created in the designer, not while running your application. Bear in mind, that this approach requires that your mock view model has a parameterless constructor. But the same is the case in the example given above in the answer.Eggleston
@René your approach is much better. Please add it as an answer and I will vote for itCobbler
@Infare this answer probably gets a lot of views & people may copy it blindly; you really should revise it for some of the comments.Kirschner
It may be possible to use the approach in https://mcmap.net/q/212483/-does-xaml-have-a-conditional-compiler-directive-for-debug-mode to only load the design-time resource in DEBUG code and not compile it for RELEASE.Kirschner
I
18

As an amalgam of Goran's accepted answer and Rene's excellent comment.

  • Add the namespace declaration. xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

  • Reference your design time data context from code.
    <Grid d:DataContext="{d:DesignInstance Type=ViewModels:MockXViewModel, IsDesignTimeCreatable=True}" ...

Invective answered 11/12, 2009 at 18:25 Comment(6)
I am tempted to mark this as the new answer, but perhaps we can pull in the rest of the details.Crake
This needs more visibility, or it needs to be pulled into the accepted answer. It's a much better solution.Persecute
Why is this better? At first I thought that the accepted answer would unnecessarily produce mock models also in runtime but I tested that and it in fact does not. Resources are not created if not used.Hyperphagia
@Paul It's really a matter of preference, but this answer keeps the whole design time data context in one declaration vs having it in two spots. Makes changes easierInvective
@JohnStritenberger Its not just preference, the accepted answer unnecessarily loads resources into memory for all time, not just for the designer.Kirschner
@UuDdLrLrSs After reviewing the accepted answer, you are correct. They're adding an instance of a class into UserControl.Resources that does, in fact, stick around foreverInvective
R
6

I use this approach for generating design time data with .NET 4.5 and Visual Studio 2013.

I have just one ViewModel. The view model has a property IsInDesignMode which tells whether design mode is active or not (see class ViewModelBase). Then you can set up your design time data (like filling an items control) in the view models constructor.

Besides, I would not load real data in the view models constructor, this may lead to issues at runtime, but setting up data for design time should not be a problem.

public abstract class ViewModelBase
{
    public bool IsInDesignMode
    {
        get
        {
            return DesignerProperties.GetIsInDesignMode(new DependencyObject());
        }
    }
}

public class ExampleViewModel : ViewModelBase
{
    public ExampleViewModel()
    {
        if (IsInDesignMode == true)
        {
            LoadDesignTimeData();
        }
    }

    private void LoadDesignTimeData()
    {
        // Load design time data here
    }       
}
Rath answered 24/7, 2015 at 6:26 Comment(0)
B
4

Karl Shifflett describes an approach that ought to work equally well for VS2008 and VS2010:

Viewing Design Time Data in Visual Studio 2008 Cider Designer in WPF and Silverlight Projects

Laurent Bugnion has a similar approach that focuses on Expression Blend. It might work for VS2010, but I haven't confirmed this yet.

Simulating data in design mode in Microsoft Expression Blend

Byzantium answered 18/6, 2010 at 18:46 Comment(3)
thanks for bringing this to my attention. I like the DesignAndRunTimeDataContext concept.Crake
Karl Shifflett has an updated article for Visual Studio 2010: Sample Data in the WPF and Silverlight DesignerViewable
The gist of the link content should really be edited into the answer, especially since the first link is now dead.Persecute
M
4

Maybe the new design-time features of Visual Studio 2010 and Expression Blend 4 are an option for you.

How it works is shown in the BookLibrary sample application of the WPF Application Framework (WAF). Please download the .NET4 version.

Michaelson answered 10/7, 2010 at 9:30 Comment(3)
Thanks for the link. Is there a particular code file or construct that I should be looking at to see the approach? (a brief overview would be great)Crake
Have a look at the BookLibrary.Presentation project. In this project you find the "DesignData" folder which is used by the UserControls in the "Views" folder.Michaelson
+1. Just had a look at this. For anyone interested the sample data view model is declared in XAML and referenced via d:DataContext="{d:DesignData Source=../DesignData/SampleLendToViewModel.xaml}"Maighdlin
C
4

Similar to the top rated answer, but better in my opinion: You can create a static property to return an instance of design data and reference it directly from XAML like so:

<d:UserControl.DataContext>
    <Binding Source="{x:Static designTimeNamespace:DesignTimeViewModels.MyViewModel}" />
</d:UserControl.DataContext>

This avoids the need to use UserControl.Resources. Your static property can function as a factory allowing you to construct non-trivial data types - for example if you do not have a default ctor, you can call a factory or container here to inject in appropriate dependencies.

Coray answered 13/2, 2017 at 6:10 Comment(0)
T
4

Using Visual Studio 2017 I have been trying to follow all of the guides and questions such as this and I was still facing a <ItemsControl> which simply did not execute the code I had inside the constructor of a DesignFooViewModel which inherits from FooViewModel. I confirmed the "did not execute" part following this "handy" MSDN guide (spoiler: MessageBox debugging). While this is not directly related to the original question, I hope it will save others a lot of time.

Turns out I was doing nothing wrong. The issue was that my application needs to be built for x64. As the Visual Studio is still in 2018 a 32-bit process and apparently cannot spin a 64-bit host process for the designer part it cannot use my x64 classes. The really bad thing is that there are no errors to be found in any log I could think of.

So if you stumble upon this question because you are seeing bogus data in with your design time view model (for example: <TextBlock Text="{Binding Name}"/> shows up Name no matter you set the property to) the cause is likely to be your x64 build. If you are unable to change your build configuration to anycpu or x86 because of dependencies, consider creating a new project which is fully anycpu and does not have the dependencies (or any dependencies). So you end up splitting most or all but the initialization parts of the code away from your "WPF App" project into a "C# class library" project.

For the codebase I am working on I think this will force healthy separation of concerns at the cost of some code duplication which is probably net positive thing.

Toni answered 2/7, 2018 at 14:54 Comment(0)
V
0

I liked jbe's suggestion, specifically to look at how they do it in the WAF framework sample apps - they use separate mock/sample view models in a DesignData folder and then have a line like this in the XAML:

mc:Ignorable="d" 
d:DataContext="{d:DesignInstance dd:MockHomeViewModel, IsDesignTimeCreatable=True}"

(where dd points to the .DesignData namespace where MockHomeViewModel lives)

It's nice and simple (which I like!) and you can inherit from the real VMs and just provide dummy data. It keeps things separate as you don't need to pollute your real VMs with any design time only code. I appreciate things might look quite different for a large project utilising IOCs etc but for small projects it works well.

But as joonas pointed out, it seems not to work with x64 builds in VS2017 and this still seems to be the case with VS2019 (I'm using V2019 16.6 Community edition). It's not fiddly to get working to start off with but can cause some head scratching when after making a change (or as is usually the case, several changes!) it suddenly stops working.

For anybody trying it, I would recommend creating a new simple WPF project (say one view, one view model, one mock vm) and play around with it; get it working and then break it. I found sometimes, no amount of solution cleans and rebuilds would fix it, the only thing that worked was closing VS down and restarting, and suddenly my design time data came back!

Verde answered 31/12, 2020 at 12:39 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.