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.
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);
}
Related
Related to this other question: How to inject an action into a command using Ninject?
Based on the comments on the above-referenced question, I take it that I would just need to create some command classes and inject them in my view model so that the view's controls just need to bind to them. I conceptually agree and understand the benefits. Besides, I wish to be as clean as possible using Ninject, DI and Constructor Injection.
Following these important rules, here's what I've come with so far.
CreateCategoryCommand
public class CreateCategoryCommand : ICommand {
public CreateCategoryCommand(CreateCategoryView view) {
if(view == null) throw new ArgumentNullException("view");
this.view = view;
}
public bool CanExecute(object parameter) { return true; }
public event EventHandler CanExecuteChanged;
public void Execute(object parameter) { view.Show(); }
private readonly CreateCategoryView view;
}
CategoriesManagementViewModel
public class CategoriesManagementViewModel {
public CategoriesManagementViewModel(ICommand createCommand) {
if (createCommand == null) throw new ArgumentNullException("createCommand");
this.createCommand = createCommand;
}
public ICommand CreateCommand { get { return createCommand; } }
private readonly ICommand createCommand;
}
So now when the CategoriesManagementView is initialized, it is constructor-injected with the CategoriesManagementViewModel, which in turn is constructor-injected with the CreateCategoryCommand, which in turn is constructor-injected with the CreateCategoryView, so no redundant dependency, neither any cycle-dependency.
Now, when I the CategoriesManagementView.CreateButton, it shall trigger the bound CategoriesManagementViewModel.CreateCommand, which will show the CreateCategoryView to the user, and this view shall have its own proper commands as well injected the same way.
Finally, this would render the RelayCommand class as useless...
Is that it?
First, I agree that RelayCommand and DelegateCommand and the like are ways of implementing commands that violate SOLID principles, so your solution here to replace them with a separate class is the correct one. Doing so also keeps your ViewModels much cleaner.
That said, you're violating MVVM pretty badly by having a class in your ViewModels layer (the CreateCategoryCommand) have knowledge of a concrete that is in your Views layer (CreateCategoryView). Nothing in your ViewModels layer should have a direct reference to anything in your Views layer.
Imagine it this way - you've separated your layers out into different dlls - Views.dll, ViewModels.dll, Models.dll, DataLayer.dll. If something in your ViewModels has a reference to a concrete in your Views, and obviously your Views will have a reference to ViewModels (as is necessary), then you have a circular reference problem.
The solution is to have your View object implement an interface (Interface Segregation Principle) like IDialog or IUiDisplay (choose the name depending on how abstract you want to be), and have your command have a dependency on that interface, NOT the direct concrete type, like so:
In Views:
public class CreateCategoryView : ..., IUiDisplay
{
...
}
In ViewModels:
public interface IUiDisplay
{
void Show();
}
public class CreateCategoryCommand : ICommand
{
public CreateCategoryCommand(IUiDisplay uiDisplay) {
if(display == null) throw new ArgumentNullException("uiDisplay");
this.display = uiDisplay;
}
private readonly IUiDisplay display;
...
}
Now, your Command no longer has a direct dependency on a concrete (so it is now mockable and testable!) from a higher layer. Now you can have your DI/IOC resolve the command dependency to the specific view class you want to inject. (I'd personally inject a view factory into the command instead, and only create the view lazily, but that's a different discussion).
One related note - if you implement commands by directly having them implement ICommand, then you're going to repeat yourself a lot (DRY). My suggestion is to create an abstract base class (CommandBase or something) that implements the requirements of ICommand. You'll find that all your commands that derive from it will only override Execute() and sometimes CanExecute(). This saves you from having to implement the event (and code to raise the event) in every command, and in many cases saves you from having to implement CanExecute since most commands just return true.
I know that in MVVM pattern (or possibly in any design pattern of this kind) we should keep our layers decoupled. From my understanding it also means, that I should keep my ViewModels separate. I'm having a bit trouble following this rule.
Say - I have a ConversationViewModel and a MessageViewModel - the former needs to create instances of the later. When ConversationViewModel gets notification about incoming message it spawns a new MessageViewModel instance and fills it with data.
The question is - if I create new MessageViewModel instances explicitly in the ConversationViewModel won't it make my app a bit harder to test? I mean - one unit of code is the ConversationViewModel and other is the MessageViewModel - I'd like to test both separate, so when somebody breaks something in the later, test for the former won't be affected. How do I achieve it?
I'm using MVVMLight, so I thought I would register MessageViewModel as an implementation of some interface, and then create a class like MockMessageViewModel implementing the same interface, but used only in tests. Then in the ConversationViewModel I'd ask the IOC container to just give me the registered implementation. Is it a good approach, or am I overreacting? Example code:
public class ViewModelLocator {
public ViewModelLocator() {
ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
if (//in test) {
SimpleIoc.Default.Register<IMessageViewModel, MockMessageViewModel>();
}
else {
SimpleIoc.Default.Register<IMessageViewModel, MessageViewModel>();
}
}
public class ConversationViewModel : ViewModelBase {
public void MessageReceived(string data) {
//I'm thinking about doing this:
var vm = SimpleIoc.Default.GetInstance<IMessageViewModel>();
// instead of doing this
var vm = new MessageViewModel();
//do stuff with vm
}
}
Whether to use interface bases approach to separate the view models from each other is the design decision based on complexity of your application.
If you want to dynamically create instance of IMessageViewModel inside IConvesationViewModel; I would recommend instead of referring to IoC container in your ViewModel class inject a factory for creating IMessageViewModel in the ConversationViewModel constructor. Later you can use this factory to create instances of IMessageViewModel. A simple implementation of factory could be Func delegate.
public class ConversationViewModel
{
private Func<IMessageViewModel> _messageViewModelFactory;
public ConversationViewModel(Func<IMessageViewModel> messageViewModelFactory)
{
_messageViewModelFactory = messageViewModelFactory;
}
public void MessageReceived(string data) {
var messageViewModel = _messageViewModelFactory();
}
}
This way you are exposing dependencies of your ConversationViewModel class through the constrctor instead of hiding them inside the class implementation.
The IoC containers like Autofac provide way to inject Func in the constructor when you create object of ConversationViewModel using it.
I believe a better way to do that is by using interfaces. You can have both your real and mock ViewModels implement the same interface and use that interface everywhere where you would use a ViewModel class.
If it was me and I may not have all the information about your application but I would have a single ViewModel IConversationViewModel. And in the IConversationViewModel I would have a collection of IMessageModel instances. I would not go nesting ViewModels.
What you can do is create the MessageViewModel immediately in ViewModelLocator and register for receiving messages in MessageViewModel using the MVVMLight MessengerInstance in its constructor. Something like this:
public class ViewModelLocator
{
public class ViewModelLocator()
{
//creates instance immediately
SimpleIoc.Default.Register<MessageViewModel>(true);
}
}
public class MessageViewModel:ViewModelBase
{
public MessageViewModel()
{
MessengerInstance.Register<string>(this,DoSomething);
}
public void DoSomething(string data)
{
//do stuff
}
}
public class ConversationViewModel:ViewModelBase
{
public void MessageReceived(string data)
{
MessengerInstance.Send<string>(data);//this will trigger DoSomething in MessageViewModel
}
}
Most of the WPF mvvm applications, we are using ICommand in the view-model. But it is referring to System.Windows.Input. so the view-model is now tightly couple with System.Windows.Input namespace. according to my understanding view-model should be able to use in normal C# winform application or asp.net application.
Normally we are using following code lines to the command with RelayCommand implementation.
private RelayCommand testCommand;// or private ICommand testCommand;
public ICommand TestCommand
{
get
{
return testCommand ??
(testCommand = new RelayCommand(param => Test()));
}
}
public void Test()
{
}
What i feel is we need to remove all the ICommand and use RelayCommand instead. So we can eliminate the System.Windows namespace from the view-model. so final code will looks like this,
private RelayCommand testCommand;
public RelayCommand TestCommand
{
get
{
return testCommand ??
(testCommand = new RelayCommand(param => Test()));
}
}
public void Test()
{
}
Any suggestions on this approach? or is there any way to eliminate the System.Windows namespace from the view-model?
Any suggestions on this approach?
This still doesn't decouple you from System.Windows.Input as RelayCommand still must implement ICommand, even if it's indirectly implementing it.
Implementing ICommand within the ViewModel is one of those things that tends to be required in order to be pragmatic. Ideally, ICommand (or a similar interface) would have been implemented in a namespace that wasn't XAML specific. That being said, it is supported directly within the Portable Class Libraries, so it is not tied to a specific framework (WPF, Silverlight, Phone, etc) as much as XAML in general.
Pretty simple to avoid coupling your ViewModel to ICommand, if you want to. Probably not a bad idea, WPF will probably go the way of MFC one day. Overkill? maybe, but here is a how:
In your view:
<StackPanel>
<Button Command="{Binding Path=MyCommand}"> Do it! Kill me Now!</Button>
<TextBlock Text="{Binding Path=Message}"></TextBlock>
</StackPanel>
Inject your ViewModel into your DataContext, Take the responsibility for the native commands, out of your view model:
public class ViewModel : INotifyPropertyChanged
{
public string Message { get; set; }
public object MyCommand { get; set; }
public void OnMyCommand(object parameter)
{
Message += "I Ran something" + Environment.NewLine;
}
public bool CanMyCommand(object parameter)
{
return true;
}
// Injected Native Command handler
public ViewModel(ICommandFactory factory)
{
MyCommand = factory.CreateInstance(OnMyCommand, CanMyCommand);
}
public event PropertyChangedEventHandler PropertyChanged;
}
Note I'm using FODY to weave in the property change handler. INotifyPropertyChanged is System.dll btw.
Now, Bind this contract:
public interface ICommandFactory
{
object CreateInstance(Action<object> action, Func<object, bool> predicate);
}
... to something that will give you a native Command object;
public class NativeCommand : ICommand
{
private readonly Action<object> _action;
private readonly Func<object, bool> _predicate;
public NativeCommand(Action<object> action, Func<object, bool> predicate)
{
_action = action;
_predicate = predicate;
}
public bool CanExecute(object parameter)
{
return _predicate(parameter);
}
public void Execute(object parameter)
{
_action(parameter);
}
public event EventHandler CanExecuteChanged;
}
public class NativeCommandFactory : ICommandFactory
{
public object CreateInstance(Action<object> action, Func<object, bool> predicate)
{
return new NativeCommand(action, predicate);
}
}
Bind<ICommandFactory>().To<NativeCommandFactory>();
VoilĂ , decoupled commands.
Also note, your injection is done at initial application start. Your ViewModel is decoupled from whatever IoC container you choose.
Well, in theory, you are pretty much right. It would if nice of ICommand was completely UI-platform-independent.
But from a practical standpoint, if you are using MVVM in a WPF app, there's a pretty good chance you are fairly dependent on WPF's databinding and datatemplating capabilities anyway. Trying to stick a WinForms UI on top of something like that would likely require a significant amount of extra effort.
I've worked on some fairly large WPF/MVVM projects in the past. We considered MVVM to be a way of separating the specific details of the UI from the code - not so that we could switch to WinForms/ASP.NET/whatever, but so that we could change the look and feel of our UI (i.e. edit the XAML) without having to change the ViewModels. In this respect, MVVM worked perfectly.
If you are really concerned about sharing code across multiple types of projects, it might be better to try and put your common code in a typical 'Business Layer'-type class library, instead of in view model.
I have a ModuleLoader : NinjectModule which is where I bind everything.
Firstly I use
Bind<Form>().To<Main>();
to Bind a System.Windows.Forms.Form to my Main form.
Is this correct?
Secondly in the Program.cs I use this:
_mainKernel = new StandardKernel(new ModuleLoader());
var form = _mainKernel.Get<Main>();
Where _mainKernel is a ninject standard kernel.
Then I use Application.Run(form)
Is this correct?
I'm unsure as to what to bind together when it comes to Windows.Forms.
Thanks for any help.
You shouldn't really be binding to System.Windows.Forms.Form. Ninject is primarily meant for binding interfaces to concrete types so that you can pass around dependencies as interfaces and switch out the concrete implementation at runtime/during tests.
If you just want to use Ninject to create your Form in this way though, you'd simply use Bind<MyForm>().ToSelf() then do kernel.Get<MyForm>(). If you are requesting the concrete type directly though and it doesn't take any dependencies, there's not much point in using Ninject to initialise it.
In your situation, if your form implements an interface then you would do: Bind<IMainForm>().To<MainForm>() and request the interface type from Ninject. Usually your interface shouldn't be bound to the concept of a "form" though, it should be agnostic of the implementation (so later you could produce a CLI and website version and simply swap the Ninject bindings).
You could use the Model-View-Presenter design pattern (or a variant) to achieve this like:
public interface IUserView
{
string FirstName { get; }
string LastName { get; }
}
public class UserForm : IUserView, Form
{
//initialise all your Form controls here
public string FirstName
{
get { return this.txtFirstName.Text; }
}
public string LastName
{
get { return this.txtLastName.Text; }
}
}
public class UserController
{
private readonly IUserView view;
public UserController(IUserView view)
{
this.view = view;
}
public void DoSomething()
{
Console.WriteLine("{0} {1}", view.FirstName, view.LastName);
}
}
Bind<IUserView>().To<UserForm>();
Bind<UserController>().ToSelf();
//will inject a UserForm automatically, in the MVP pattern the view would inject itself though
UserController uc = kernel.Get<UserController>();
uc.DoSomething();
public class StatisticsViewPresenter
{
private IStatisticsView view;
private Statistics statsModel;
public StatisticsViewPresenter(IStatisticsView view, Statistics statsModel)
{
this.view = view;
this.statsModel = statsModel;
}
}
I don't use events (but am willing to if it can solve my problem), so my View classes look like this:
public class StatisticsForm : Form, IStatisticsView
{
public StatisticsForm()
{
InitializeComponent();
}
[Inject]
public StatisticsViewPresenter Presenter
{
private get;
set;
}
}
With
kernel.Bind<StatisticsPresenter>().ToSelf().InSingletonScope();
kernel.Bind<IStatisticsView>().To<StatisticsForm>();
kernel.Get<IStatisticsView>();
it builds up the Form, builds up the presenter, then injects the presenter into the Presenter property. Everything's peachy. (Except for that singleton-scoped presenter--any thoughts on a better way to do that? Perhaps just manually inject the presenter into the view's Presenter property inside the presenter's constructor: this.view.Presenter = this).
But if I turn StatisticsForm into StatisticsUserControl and drag-drop it onto my MainForm, it's not being injected into MainForm by Ninject, it's simply being new'd by the Designer. I see three solutions here:
1) Don't use UserControls and just use one giant form that implements these multiple views (eww);
2) Inject UserControls into my form and lose Designer support;
3) Your solution! :)
My approach to use Ninject with forms, usercontrols and the designer is:
Use factories to create the forms (also for the usercontrols if you create some controls dinamically)
for the usercontrols and the forms keep the constructors without parameters and use property injection
add an Activation strategy to the kernel that check if ninject has just created a form or a usercontrol. If that is the case, the activation strategy iterates over the controls in the Controls property of the UserControl (or the Form) and calls Kernel.Inject(UserControl) for each usercontrol. (An Activation strategy is some code ninject executes after it has injected an object)
You can use the designer and have forms and usercontrols with dependencies injected via Ninject.
The only drawback is that you have to use property injection instead of constructor injection for the usercontrols (and the forms)
namespace Majiic.Ninject
{
public class WindowsFormsStrategy : ActivationStrategy
{
// Activate is called after Kernel.Inject
//even for objects not created by Ninject
//To avoid multiple "injections" in the same nested controls
//we put this flag to false.
private bool _activatingControls = false;
public override void Activate(IContext context, InstanceReference reference)
{
reference.IfInstanceIs<UserControl>(uc =>
{
if (!_activatingControls)
{
Trace.TraceInformation("Activate. Injecting dependencies in User control of type {0}", uc.GetType());
_activatingControls = true;
context.Kernel.InjectDescendantOf(uc);
_activatingControls = false;
}
});
reference.IfInstanceIs<Form>(form =>
{
if (!_activatingControls)
{
Trace.TraceInformation("Activate. Injecting dependencies in Form of type {0}", form.GetType());
_activatingControls = true;
context.Kernel.InjectDescendantOf(form);
_activatingControls = false;
}
});
}
}
}
Create the kernel and add the Activation Strategy
var kernel=new StandardKernel(new CommonMajiicNinjectModule());
kernel.Components.Add<IActivationStrategy, WindowsFormsStrategy>();
kernel extensions to iterate over descendents controls
namespace Majiic.Ninject
{
static public class WinFormsInstanceProviderAux
{
static public void InjectDescendantOf(this IKernel kernel, ContainerControl containerControl)
{
var childrenControls = containerControl.Controls.Cast<Control>();
foreach (var control in childrenControls )
{
InjectUserControlsOf(kernel, control);
}
}
static private void InjectUserControlsOf(this IKernel kernel, Control control)
{
//only user controls can have properties defined as n-inject-able
if (control is UserControl)
{
Trace.TraceInformation("Injecting dependencies in User Control of type {0}", control.GetType());
kernel.Inject(control);
}
//A non user control can have children that are user controls and should be n-injected
var childrenControls = control.Controls.Cast<Control>();
foreach (var childControl in childrenControls )
{
InjectUserControlsOf(kernel, childControl );
}
}
}
}
This is certainly an interesting area of, should I say, research. We've made ourselves a solution where we host user controls in a generic form.
Our generic form is not intended for use with the Designer. Through code we add the chosen user control to the Form dynamically.
For other frameworks you should look at Prism/Composite from the Microsoft Patterns & Practices group. Here's an article discussing extensions for WinForms.
I recently created some reuseable UserControls with the need of Dependencies to inject. As the IoC Container isn't used to create those UserControls, obviously he cannot automatically inject the Dependencies.
My Solution is, a Base-Class to enable at least Property Injection. Constructor Injection is not supported, as a parameterless Constructor is used to create those instances.
public class NinjectUserControl : UserControl
{
// Generally this is considered to be a bad practice,
//however I didn't find any better way. If you do, please share :)
public static IKernel Kernel { private get; set; }
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
RequestActivation(Kernel);
}
protected virtual void RequestActivation(IKernel kernel)
{
kernel?.Inject(this);
}
}
To get it to Work you need to set the Kernel once. Typically this is somewhere inside your program.cs (WinForms) or App.xaml.cs (WPF)
IocKernel = new StandardKernel(); // typically a static member
NinjectUserControl.Kernel = IocKernel;
IocKernel.Load(new Module()); // loading modules
// .. Create MainForm or whatever
To use, simply inherit NinjectUserControl and then let the Kernel Inject your dependencies via Property Injection:
[Inject]
public IService Service { private get; set; }
please note, that those dependencies are not accessible inside the Constructor.