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! :)
Dependency Injection is done by supplying the DEPENDENCY through the class's constructor when creating the instance of that class. The injected component can be used anywhere within the class. Recommended to use when the injected dependency, you are using across the class methods.
Constructor injection should be the main way that you do dependency injection. It's simple: A class needs something and thus asks for it before it can even be constructed.
You can take advantage of the ServiceFilter attribute to inject dependencies in your controller or your controller's action methods.
A basic benefit of dependency injection is decreased coupling between classes and their dependencies. By removing a client's knowledge of how its dependencies are implemented, programs become more reusable, testable and maintainable.
My approach to use Ninject with forms, usercontrols and the designer is:
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With