Search code examples
c#wpfdesign-timewindow-managerseventaggregator

Design Time Support with Event Aggregator AND WIndowManager


I have to create a WPF application with Caliburn.Micro 2.0.2 for my Bachelor exam.

In this application three different Views will be shown in a single Shell (Window) and they have to communicate with each other. So I need the Event Aggregator. I also need the Window Manager to show additional dialogs.

My actual problem is that I have to bring all this together with full Design Time Support. Unfortunately there is no example for that case.

The documentation of Caliburn.Micro says that a default constructor is needed in the view model, to provide design time support. However the Event Aggregator and the Window Manager are used as constructor parameters in the view model, so there is no default constructor at first.

The documentation also says that in such a case the ViewModelLocator should be used to get Design Time Support. Unfortunately the section about the ViewModelLocator doesn't give me enough information about how to do that.

Another idea might be to chaining constructors like this:

public class ExampleViewModel : PropertyChangedBase
{
    private readonly IEventAggregator eventAggregator;
    private readonly IWindowManager windowManager;

    public ExampleViewModel() : this(null)
    {
    }

    public ExampleViewModel(IEventAggregator eventAggregator) : this(eventAggregator, null)
    {
    }

    public ExampleViewModel(IEventAggregator eventAggregator, IWindowManager windowManager)
    {
        this.eventAggregator = eventAggregator;
        this.windowManager = windowManager;

        // doing everything needed for the Design Time Support
    }
}

But I have no idea if that will work at last.

I hope somebody here can help me with this issue.


Solution

  • You can use a separate DataContext (ViewModel) for design time. You need to add in your XAML where the view model is used:

    <UserControl 
        ...
        xmlns:dt="clr-namespace:YourProject.DesignTimeHelpers;assembly=YouAssembly"
        d:DataContext="{Binding Source={x:Static dt:DesignTimeModels.ExampleViewModelForDesignTime}}">
    

    There is the DesignTimeModels static class with the view model:

    public static class DesignTimeModels
    {
        public static ExampleViewModel ExampleViewModelForDesignTime { get; set; }
    
        // static constructor
        static DesignTimeModels()
        {
            ExampleViewModelForDesignTime = 
                new ExampleViewModel(new EventAggregator(), new WindowManager());
        }
    }
    

    The main idea is creating an instance of the view model by a static initializer with arguments what you need.

    If you would like to use a IoC container (Caliburn for example) for instantination of the EventAggregator or the WindowManager, you can use a ServiceLocator pattern. For example:

    // static constructor
    static DesignTimeModels()
    {
        var eventAggregator = ServiceLocator.Get<IEventAggregator>();
        var windowManager = ServiceLocator.Get<IWindowManager>();
    
        ExampleViewModelForDesignTime = 
            new ExampleViewModel(eventAggregator , windowManager);
    }