[WPF / MVVM] How to get data in “design time” ?
When you are working with WPF and MVVM Pattern, you can regret that the designer doesn’t get data, in design time, that allow him to simply modified the graphical interface.
To help my developments, I’ve created a little attached property which will create an instance of the type passed in parameter:
public static class DesignTimeHelper
{
/// <summary>
/// DependencyProperty used to store the DesignTime property.
/// </summary>
public static readonly DependencyProperty DesignTimeDataProperty =
DependencyProperty.RegisterAttached("DesignTimeData", typeof(Type), typeof(DesignTimeHelper), new FrameworkPropertyMetadata(null, new PropertyChangedCallback(OnDesignTimeDataChanged)));
/// <summary>
/// Gets the design time data.
/// </summary>
/// <param name="obj">The obj.</param>
/// <returns></returns>
public static Type GetDesignTimeData(DependencyObject obj)
{
return (Type)obj.GetValue(DesignTimeDataProperty);
}
/// <summary>
/// Sets the design time data.
/// </summary>
/// <param name="obj">The obj.</param>
/// <param name="value">The value.</param>
public static void SetDesignTimeData(DependencyObject obj, Type value)
{
obj.SetValue(DesignTimeDataProperty, value);
}
/// <summary>
/// Called when DesignTimeData changed.
/// </summary>
/// <param name="d">The source object.</param>
/// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
private static void OnDesignTimeDataChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var isOnDesignMode = DesignerProperties.GetIsInDesignMode(new DependencyObject());
if (isOnDesignMode)
{
var element = d as FrameworkElement;
if (element == null)
throw new NullReferenceException("element must not be null and must be an UIElement.");
var designTimeDataType = e.NewValue as Type;
if (designTimeDataType == null)
throw new NullReferenceException("designTimeDataType must not be null.");
element.DataContext = Activator.CreateInstance(designTimeDataType);
}
}
}
To use this attached property, it’s simple: just create 2 ViewModels (one used for the data in “runtime” and the second one used for the data in “designtime”):
Then, use the property:
At “design time”, we can see that data are really different from “runtime”:
For your information, here is the content of the ViewModel in “design” mode:
namespace TestToolbox.ViewModels.Design
{
class SampleViewModel : ISampleViewModel
{
#region ISampleViewModel Members
public string Text
{
get { return "Design time text"; }
}
public string Title
{
get { return "Design time title"; }
}
#endregion
}
}
And here is the ViewModel for “runtime” mode:
namespace TestToolbox.ViewModels
{
public class SampleViewModel : ISampleViewModel
{
#region ISampleViewModel Members
public string Text
{
get { return "Runtime text"; }
}
public string Title
{
get { return "Runtime title"; }
}
#endregion
}
}
That’s all ! Now, your designer is able to work with (sample) data that allow him to design the graphical interface of your application without having to launch it for testing/viewing the results.
Bye !
PS: Thanks to Simon for the suggestion of using a type instead of a simple string [;)]