Could I get help with a little issue I am encountering regarding splitting projects into different tiers. In my ViewModel logic I have code where I create a new instance of a window when a button is clicked (I use ICommand interface for that)
The problem is however, that this requires my View folder which is in the presentation layer, I can’t reach it as my presentation layer is dependent on my ViewModel in the logic layer.
I would just move the code that deals with the creation of the pages to the view code behind but I also pass the current instance of a viewmodel as a parameter for that new window being created (for eventhandling purposes).
Any help is much appreciated! Thanks.
A view model shouldn't create instances of windows. What you could do is to inject your view model with a service that is responsible for creating windows, e.g.:
public class MainWindowViewModel
{
private readonly IWindowService _windowService;
public MainWindowViewModel(IWindowService windowService)
{
_windowService = windowService;
CreateWindowCommand = new DelegateCommand(() =>
{
_windowService.CreateWindow(new SomeViewModel());
});
}
public ICommand CreateWindowCommand { get; }
}
Define the IWindowService interface in the view model project and the concrete implementation of it in the view/presentation project:
public class WindowService : IWindowService
{
public void CreateWindow(SomeViewModel vm)
{
Window win = new Window();
win.DataContext = vm;
win.Show();
}
}
I am trying to startup an simple Model View Presenter WinForms application and use the constructor injection to inject IMainView, IEventPublisher and IRepository to the main presenter.
However, I am having some problems to find out how to exactly do this. My problem is that for some reason presenter seems to create two instances of the view or view is created and not shown.
Program.cs
var kernel = new StandardKernel();
kernel.Load(Assembly.GetExecutingAssembly());
//var view = kernel.Get<View.MainForm>();
var presenter = kernel.Get<Presenter>();
//Application.Run(view);
Application.Run();
If view is initialized on the program.cs, then also presenter creates its own view? And with the active approach above, the view is created but not shown.
Presenter.cs
public Presenter(IMainForm view,
IRepository repository,
IEventPublisher eventPublisher)
{
_view = view;
_repository = repository;
_reactiveEventPublisher = eventPublisher;
}
MainForm.cs
public Form(IEventPublisher eventPublisher)
{
_reactiveEventPublisher = eventPublisher;
}
NinjectBindings.cs
public class NinjectBindings : NinjectModule
{
public override void Load()
{
Bind<IRepository>().To<Repository>();
Bind<IMainForm>().To<View.MainForm>();
Bind<IEventPublisher>().To<ReactiveEventAggregator>().InSingletonScope();
Bind<Presenter>().ToSelf();
}
}
Question is, what is the proper way to start WinForms application in case the view is injected to the presenter?
Using Ninject 3.3.4 as IoC container.
If view is initialized on the program.cs, then also presenter creates
its own view?
This is because of the object scoping. If you request an IMainForm in Program.cs, and then request a Presenter, then Ninject will inject a new instance of View.MainForm for the Presenter and thus you have two instances of the view. To use the same instance you need to scope the binding in singleton scope.
Bind<IMainForm>().To<View.MainForm>().InSingletonScope();
When requesting an instance of the view, ensure you do so via your binding, i.e. var view = kernel.Get<View.IMainForm>(); otherwise Ninject will try to self-bind and will be dodging your singleton scope.
I'm creating a WPF MVVM application using Simple Injector as DI container. Now I'm having some issues when I'm trying to resolve a view from Simple Injector, because I'm in need of passing a parameter into my constructor at construction time (not when registering the view to the container, thus this is not applicable: Simple Injector pass values into constructor).
What I'm after is something like this:
var item = container.GetInstance<MyType>(myParameter);
I've read several places that this is not possible in Simple Injector because it should not be done (including here: https://simpleinjector.codeplex.com/discussions/397080).
Is this true, and if so, how could I do this instead?
Background information
I have a collection of multiple view models and models which are looked up by a specific key, and the parameter I want to pass into the view is the key for the view model to use. I've found this necessary because the view models and the models are used in multiple locations of the application, and need to stay in sync / be the same instances if they have the same key. I don't think I'm able to use lifetime scope to solve this, and there is no way I know the keys when I'm registering to the container. I've also understood that the ViewModelLocator approach might be the ServiceLocator (anti-?)pattern, however, currently it is the best I've got.
My constructor currently looks like this, and I want the IViewModelLocator to be resolved, while I pass in the key:
public FillPropertiesView(IViewModelLocator vml, object key)
{
// .. Removed code
// Assign the view model
var viewModel = vml.GetViewModel<FillPropertiesViewModel>(key);
DataContext = viewModel;
}
The IViewModelLocator looks like the following (and a similar interface exists for models).
public interface IViewModelLocator
{
// Gets the view model associated with a key, or a default
// view model if no key is supplied
T GetViewModel<T>(object key = null) where T : class, IViewModel;
}
Now I have the following questions:
What is the best way to be able to resolve the view with the view model key?
Do I have to do some refactoring to enable this?
Am I missing out on some of the power of the DI container since I have created my own dictionary based ViewModelLocator?
Extended information
I have shown the ViewModelLocator above, and the reason I'm using this is to keep blendability (basically it just provides me with design time data when opened in Blend). The runtime view model could have been the same for every instance of the view (not dependent on the key), if I did not have to have different windows opened at the same time (see next paragraph). The issue described above, however, is the same when the ViewModel is fetching a model, and the ModelLocator needs a key to fetch an existing model if it exists.
This is part of a VSTO application targeting PowerPoint (which affects some parts of the design). When an object on screen is selected, a task panel is opened (this is basically the FillPropertiesView explained above). The object that is selected has a key that is supplied to the view, in order for the view to extract the correct view model from the ViewModelLocator. The view model will then get a reference to a model by using a IModelLocator (similar to the IViewModelLocator) and the same key. At the same time, a controller will fetch the model from the ModelLocator by using the same key. The controller listens to change events from the model and updates the objects on screen. The same process is replicated whenever a new object is selected, and at the same time multiple windows could be open that interacts with the same or different objects simultaneously (that is, with multiple task panes all with unique view models).
Up until now I have resolved the view with a default, parameterless constructor, and then injected the view model with a method call afterwards:
// Sets the view model on a view
public void SetViewModel(IViewModelLocator vml, object key)
{
// Assign the view model
_viewModel = vml.GetViewModel<FillPropertiesViewModel>(key);
DataContext = _viewModel;
}
I never had to register the view with the container, but resolved the concrete type like this:
string key = "testkey" // read from the selected object
var view = container.GetInstance<FillPropertiesView>();
var vml = container.GetInstance<IViewModelLocator>();
view.SetViewModel(vml, key);
This issue surfaced when I tried to refactor this so that I did not have to call the SetViewModel() method every and manually resolve the view models etc. It got very messy when I also had to do this manual initiation within the view model to initiate the model in the same way.
ViewModelLocator
The ViewModelLocator is currently working as a wrapper around the DI container, i.e. the view models are registered in Simple Injector.
The registrations are like the following (in a class called CompositionHost):
container.RegisterSingle<IViewModelLocator, ViewModelLocator>();
container.RegisterSingle<IModelLocator, ModelLocator>();
The implementation looks like this:
// Base implementation used by ViewModelLocator and ModelLocator
public class ServiceLocator<TService> where TService : class
{
private readonly Dictionary<CombinedTypeKey, TService> _instances =
new Dictionary<CombinedTypeKey, TService>();
// Gets a service instance based on the type and a key.
// The key makes it possible to have multiple versions of the same service.
public T GetInstance<T>(object key = null) where T : class, TService
{
var combinedKey = new CombinedTypeKey(typeof(T), key);
// Check if we already have an instance
if (_instances.ContainsKey(combinedKey))
{
return _instances[combinedKey] as T;
}
// Create a new instance
// CompositionHost is a static reference to the DI container (and
// should perhaps be injected, however, that is not the main issue here)
var instance = CompositionHost.GetInstance<T>();
_instances.Add(combinedKey, instance);
return instance;
}
// A combined key to ease dictionary operations
private struct CombinedTypeKey
{
private readonly object _key;
private readonly Type _type;
public CombinedTypeKey(Type type, object key)
{
_type = type;
_key = key;
}
// Equals and GetHashCode() are overridden
}
}
public class ViewModelLocator : IViewModelLocator
{
private readonly ServiceLocator<IViewModel> _viewModelLocator;
public ViewModelLocator(ServiceLocator<IViewModel> locator)
{
_viewModelLocator = locator;
// Dummy code that registers design time data is removed
}
// IViewModel is just an empty interface implemented by the view models
public T GetViewModel<T>(object key = null) where T : class, IViewModel
{
return _viewModelLocator.GetInstance<T>(key);
}
}
Injecting a service locator into your classes is (almost) never the way to go, because this disallows compile time checking of dependencies and runtime dependency analysis. For that reason I can also advice to register ALL your root types (such as your views) since otherwise Simple Injector is left in the dark and is not able to advice you about any possible misconfigurations that you might have.
Since you have View + ViewModel pairs that are always cached together, but might depend on Model instance that are reused by multiple View + ViewModel pairs, I suggest the following design.
Define an abstraction for views and view models:
public interface IView<TModel>
{
IViewModel<TModel> ViewModel { get; }
}
public interface IViewModel<TModel>
{
TModel Model { get; set; }
}
Define an abstraction for retrieving/caching view by key.
public interface IViewProvider<TView, TModel> where TView : IView<TModel>
{
TView GetViewByKey(object key);
}
With these abstractions your view can look as follows:
public class FillPropertiesView : IView<FillPropertiesModel>
{
public FillPropertiesView(FillPropertiesViewModel viewModel)
{
this.ViewModel = viewModel;
}
public IViewModel<FillPropertiesModel> ViewModel { get; private set; }
}
And your controllers can depend upon the IViewProvider<TView, TModel> abstraction so they can reload the view when a new key is coming in:
public class FillPropertiesController : Controller
{
IViewProvider<FillPropertiesView, FillPropertiesModel> viewProvider;
FillPropertiesView view;
public FillPropertiesController(
IViewProvider<FillPropertiesView, FillPropertiesModel> provider) {
this.viewProvider = provider;
}
public void Reinitialize(object key) {
this.view = this.viewProvider.GetViewByKey(key);
}
}
The implementation for IViewProvider<TView, TModel> could look like this:
public class ViewProvider<TView, TModel> : IViewProvider<TView, TModel>
where TView : class, IView<TModel> {
Dictionary<object, TView> views = new Dictionary<object, TView>();
Container container;
IModelProvider<TModel> modelProvider;
public ViewProvider(Container container,
IModelProvider<TModel> modelProvider) {
this.container = container;
this.modelProvider = modelProvider;
}
public TView GetViewByKey(object key) {
TView view;
if (!this.views.TryGetValue(key, out view)) {
this.views[key] = view = this.CreateView(key);
}
return view;
}
private TView CreateView(object key) {
TView view = this.container.GetInstance<TView>();
view.ViewModel.Model = this.modelProvider.GetModelByKey(key);
return view;
}
}
This implementation depends on a (previously undefined) IModelProvider<TModel> abstraction. This is basically your old ModelLocator, but by using a generic type you can make the implementation much easier, because we can have one instance of this type per TModel (the same holds for ViewProvider), which saves you from having to do things with storing elements with the { Type + key } combination.
You can register this all as follows:
Assembly asm = Assembly.GetExecutingAssembly();
container.RegisterManyForOpenGeneric(typeof(IView<>), asm);
container.RegisterManyForOpenGeneric(typeof(IViewModel<>), asm);
container.RegisterOpenGeneric(typeof(IViewProvider<,>),
typeof(ViewProvider<,>), Lifestyle.Singleton);
container.RegisterOpenGeneric(typeof(IModelProvider<>),
typeof(ModelProvider<>), Lifestyle.Singleton);
var controllers =
from type in asm.GetTypes()
where type.IsSubClassOf(typeof(Controller))
where !type.IsAbstract
select type;
controllers.ToList().ForEach(t => container.Register(t));
container.Verify();
With RegisterManyForOpenGeneric you let Simple Injector search the supplied assemblies to look for implementations of the given open generic abstraction and Simple Injector will batch-register them for you. With RegisterOpenGeneric you specify an open-generic abstraction and tell Simple Injector which implementation to use when a close-generic version of that abstraction is requested. The last line searches through your application to look for all controller types and registers them in the system.
Let me have two very basic objects like:
public class View
{
public View(Controller controller)
{
// Use the model exposed by the controller here
}
}
public class Controller
{
private readonly IView view;
public Controller()
{
this.view = new View(this);
}
public Controller(View v)
{
this.view = v;
}
}
Later I decide to inject View object into the Controller via DI but there I have a cyclic dependency (i.e. I can't use var ctrl = new Controller(new View(ctrl));). How would you go about injectin the dependency in this case?
The most common solution is to use a dependency property to solve circular dependencies. i.e. create a new property in one of the classes and let the IoC container assign it.
If you are using Unity you should add [Dependency] to that property.
A sidenote: A View should not have a dependency to a controller. It should not be aware of it at all.
Update in reply to comment
You can't. That's the problem with circular dependencies. The only other solution is to use composition. That is to break out the common functionality into a separate class and include it in both the controller and the view.
I actually found a nice solution using Ninject.
public class Controller
{
private readonly View view;
public Controller(ViewModule viewModule)
{
using (IKernel kernel = new StandardKernel(viewModule))
{
this.view = kernel.Get<View>(new ConstructorArgument("controller", this);
}
}
}
Where the ViewModule is a pre-configured Ninject module to resolve the particular view dependency (GUI, CLI, etc.) Minor problem here is that, I'm now dependent on the particular DI framework.
You can't do that at all with constructor-injection
If you change the constructor of the controller to
public Controller(IView view)
in which order would you create the two objects?
View needs the controller Instance and the controller needs the view.
However, you can make the IView Property of the controller public, and set the Property after creation (Some DI-Containers can do this for you automatically when you set the correct attribute).
i am familier with mvc,mvp or mvvm patter. so i was searching google for implementing good design patter for win form apps. i found lots of article.few guys said mvc is good and few guys said mvp is perfect for win apps. i found a very small code which implement mvp in win apps. i go through the code and found that developer has to write lot of extra code to bind treeview or any control.
the code as follows
public interface IYourView
{
void BindTree(Model model);
}
public class YourView : System.Windows.Forms, IYourView
{
private Presenter presenter;
public YourView()
{
presenter = new YourPresenter(this);
}
public override OnLoad()
{
presenter.OnLoad();
}
public void BindTree(Model model)
{
// Binding logic goes here....
}
}
public class YourPresenter
{
private IYourView view;
public YourPresenter(IYourView view)
{
this.view = view;
}
public void OnLoad()
{
// Get data from service.... or whatever soruce
Model model = service.GetData(...);
view.BindTree(model);
}
}
please someone go through the code and help me to understand the flow because how code should be written in mvp patter that i dont know. thanks.
This code is already using the MVP pattern.
It declares an interface IYourView and a concrete class YourView that implements System.Windows.Form and this new interface. Essentially what that is doing is creating a new form with the added requirement that it also implements the BindTree() method defined in IYourView.
The YourView class (form) then has a dependency of YourPresenter in order to hook up the OnLoad event with the presenter, although I'd do it where the presenter subscribes to the form's OnLoad event instead.
The presenter YourPresenter takes as a dependency an instance of YourView and it can then use that instance in the rest of its logic.
Now, to use that you would follow a process similar to this:
Create a new instance of YourView (which then in turn creates the presenter)
Implement logic in the presenter (ie- create GetModel()) to create the Model that you want to bind to the tree
Call view.BindTree(model) in the presenter where model is what you just created in the previous step
So, create an instance of your view:
IYourView newView = new YourView();
Then in your presenter class:
Model model = GetModel();
newView.BindTree(model);