Peter
Peter

Reputation: 38515

MVVM setup design time services?

I'm working with the MVVM pattern + a simple ServiceLocator implementation, now to my problem how am I supposed to setup the services when the views are running in design time?

Iv tried this but it does not seem to work in VS 2010 or some thing, I know it worked on my old computer but on my new it does not. so does any one know a good alternative?

Edit: (On behalf of Merlyn Morgan-Graham)

Well what I'm trying to do is this, I have my view, ViewModel and services now the difference here is that I have 2 implementations of each service one for design time and one for run time. for a better explanation look here.

Upvotes: 1

Views: 554

Answers (3)

Michael Sander
Michael Sander

Reputation: 2722

Also I do agree to all who have concerns regarding the use of the service locator at design time, I do believe that this is a valid scenario in some use cases. This is not a discussion on why/why not, this is simple the way it (almost) worked for me. There is still a problem which I did not solve yet: this only works for one view at a time.

  1. Create a simple bootstrapper for setting up your IoC of choice. Notice the ISupportInitialize interface.

    public class Bootstrapper: ISupportInitialize
    {
        #region ISupportInitialize Members
    
        public void BeginInit() { }
    
        public void EndInit()
        {
            if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
                Setup();
        }
    
        #endregion
    
        public static void Setup() { SetupServiceLocator(); }
    
        static void SetupServiceLocator()
        {
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<ConfigService>().As<IConfigService>().ExternallyOwned().SingleInstance();
            IContainer container = builder.Build();
    
            ServiceLocator.SetLocatorProvider(() => new AutofacServiceLocator(container));
        }
    }
    
  2. Use the Bootstrapper as before for runtime mode, e.g.:

    public partial class App : Application
    {
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            Bootstrapper.Setup();
        }
    }
    
  3. Additionally you need to add it to the application resources for design mode support:

    <Application x:Class="MonitoringConfigurator.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:local="clr-namespace:MyBootstrapperNamespace"
                 StartupUri="MainWindow.xaml">
        <Application.Resources>
            <local:Bootstrapper x:Key="Bootstrapper" />
        </Application.Resources>
    </Application>
    

Upvotes: 0

Merlyn Morgan-Graham
Merlyn Morgan-Graham

Reputation: 59131

If you want to decouple your view from your viewmodel, and your viewmodel from your model/dal (basically, if you want to use MVVM), then your view model and data model shouldn't know anything about design time. Design time only applies to the view.

This article shows a way to define your design time data via XML/XAML, so your code underneath doesn't have to know anything about it:

http://karlshifflett.wordpress.com/2009/10/21/visual-studio-2010-beta2-sample-data-project-templates/

After Edit: It turns out that you'll still have to use your view model for your existing XAML bindings to work. This will just populate the view model rather than having to create a new data model. I'm not sure, but there might be classes that allow you to use the WPF binding mechanism to take care of this... Views?

Resume Before Edit...: As far as the solution in the article you linked first, the designer doesn't instantiate anything but your class, and the code it references. That means that assembly attributes won't be instantiated unless your view code somehow directly references them.

If you really want to couple your view models to your views during design time, and make it so that design time services are registered, then you have to place the service registration code in your view class, or a class the view class directly references.

To do that, you could use static constructors of your views to register your design time services. You could also write a static method on some other class (application?) to (conditionally) register the design time services. Then, call that method in the constructor of your views.

Or you could simply register them in the constructor for each of your views.

Basically, what you want to do is possible, but that method linked in the first article isn't. If you read farther in the comments, you'll see that his method is broken.

You may also want to question the idea of hooking your view model to your view during design time, because the MVVM pattern was made to avoid that sort of thing.

Upvotes: 1

Thomas Levesque
Thomas Levesque

Reputation: 292575

You usually don't need to access services at design-time... Typically, you don't even use your real ViewModels at design-time, you use dummy design data, as explained here. If you really need to use your real ViewModels, you can implement dummy versions of your services, and use them instead of the real services :

if (DesignerProperties.GetIsInDesignMode(new DependencyObject()))
{
    // Design time
    ServiceLocator.Instance.Register<IService1>(new DummyService1());
    ServiceLocator.Instance.Register<IService2>(new DummyService2());
}
else
{
    // Run time
    ServiceLocator.Instance.Register<IService1>(new RealService1());
    ServiceLocator.Instance.Register<IService2>(new RealService2());
}

Upvotes: 0

Related Questions