What is the correct way to initialize a model and view in WPF CAL MVVM
I have come accross two ways of initializing Views and ViewModels in WPF CAL MVVM.
1 - Seems to be more popular. Requires you to resolve the ViewModel to automatically resolve the View. The ViewModel contains information about the View.
public interface IView
{
void SetModel(IViewModel model);
}
public interface IViewModel
{
IView View { get; }
}
public class View
{
public void SetModel(IViewModel model)
{
this.DataContext = model;
}
}
public class ViewModel
{
private IView view;
public ViewModel(IView view)
{
this.view = view;
}
public IView View { return this.view; }
}
2 - Seems a lot cleaner and removes the View from the ViewModel. Requires you to resolve the View to automatically resolve the ViewModel. Injects objects into the view (Not sure if this is good or not).
public interface IView
{
}
public interface IViewModel
{
}
public class View
{
private IViewModel model;
public View(IUnityContainer unityContainer)
{
this.model = unityContainer.Resolve<IViewModel>();
this.DataContext = t开发者_如何学编程his.model;
}
}
public class ViewModel
{
}
What is the accepted method of initializing the views and models and what are the advantages and disadvantages of each method. Should you be injecting objects into your view?
They are both valid, but #1 tends to be more testable (it at least makes your tests more concise). The advantage to #2 is that it tends to be more explicit and makes maintenance a little more clear, especially when you have a lot of turnover, that kind of thing. Takes less explaining (though this is not a reason to adopt it, it's just a truism).
The difference is that #1 is called Dependency Injection and #2 is called Service Location. They are often confused because they both generally utilize some sort of IoC container (although this doesn't have to be the case).
It's a matter of preference in the end, but as I said I think you will find #1 a lot easier to test... you won't have to involve the IUnityContainer interface in your testing / mocking.
Option 1 looks about right, give the view a reference to the viewmodel.
Having viewmodels with a reference back to the view seems a bit fishy to me though. That looks more like a model-view-presenter type architecture. If you've got viewmodels that interact heavilly with the view and need a reference to the view for that you might be better off splitting the viewmodel in a viewmodel used purely for databinding and a presenter that does more complex interaction.
Option 2 doesn't look right at all. Passing a reference to the ioc container into classes is a big code smell in my book. Calls to an IoC container should be minimized. In most of my applications I only call into the container at the start of the program to wire stuff up. More dynamic object creation is usually done with factory classes.
I prefer to define the view model in XAML and provide a read-only property for typed access:
<UserControl ...>
<UserControl.DataContext>
<local:MyViewModel/>
</UserControl.DataContext>
...
</UserControl>
public partial class MyView : UserControl, IMyView
{
public MyViewModel ViewModel
{
get { return this.DataContext as MyViewModel; }
}
...
}
The problem with this code is that option 2 is baking in more than it needs to. It really doesn't need and shouldn't have a reference to the container.
An alternative allows option 2 to be as testable as option 1, but conceptually clearer in that the ViewModel never knows about the View.
This is particularly useful if you want to specify your layout using an xml file as opposed to using the prism regions, which allows you to make the layout easily configurable.
Alternative:
public interface IView
{
}
public interface IViewModel
{
}
public class View : IView
{
private IViewModel model;
public View(IViewModel m)
{
this.model = m;
this.DataContext = this.model;
}
}
public class ViewModel : IViewModel
{
}
and somewhere else you have:
Container.RegisterType<IViewModel, ViewModel>( /* appropriate container config */ );
Container.RegisterType<IView, View>(/* appropriate container config */ );
and you could create a view anywhere with:
Container.Resolve<IViewModel>();
精彩评论