6
public class StatisticsViewPresenter
{
    private IStatisticsView view;
    private Statistics statsModel;

    public StatisticsViewPresenter(IStatisticsView view, Statistics statsModel)
    {
        this.view = view;
        this.statsModel = statsModel;
    }
}

我不使用事件(但如果它可以解决我的问题我愿意),所以我的视图类看起来像这样:

public class StatisticsForm : Form, IStatisticsView
{
    public StatisticsForm()
    {
        InitializeComponent();
    }

    [Inject]
    public StatisticsViewPresenter Presenter
    {
        private get;
        set;
    }
}

kernel.Bind<StatisticsPresenter>().ToSelf().InSingletonScope();
kernel.Bind<IStatisticsView>().To<StatisticsForm>();
kernel.Get<IStatisticsView>();

它构建 Form,构建 Presenter,然后将 Presenter 注入 Presenter 属性。一切都很美好。(除了那个单例范围的演示者——有什么更好的方法吗?也许只是手动将演示者注入到演示者构造函数内的视图的演示者属性中:this.view.Presenter = this)。

但是,如果我将 StatisticsForm 转换为 StatisticsUserControl 并将其拖放到我的 MainForm 上,它不会被 Ninject 注入到 MainForm 中,它只是由 Designer 新建。我在这里看到三个解决方案:

1) 不要使用 UserControls,而只使用一个实现这些多个视图的巨型表单 (eww);

2) 将 UserControls 注入我的表单并失去 Designer 支持;

3)您的解决方案!:)

4

3 回答 3

4

我将 Ninject 与表单、用户控件和设计器一起使用的方法是:

  • 使用工厂创建表单(如果您动态创建一些控件,也可以用于用户控件)
  • 对于用户控件和表单,保持构造函数不带参数并使用属性注入
  • 向内核添加一个激活策略,检查 ninject 是否刚刚创建了表单或用户控件。如果是这种情况,激活策略会遍历 UserControl(或 Form)的 Controls 属性中的控件,并为每个用户控件调用 Kernel.Inject(UserControl)。(激活策略是在注入对象后执行的一些代码 ninject)

您可以使用设计器并拥有通过 Ninject 注入依赖项的表单和用户控件。

唯一的缺点是您必须为用户控件(和表单)使用属性注入而不是构造函数注入

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;
            }
        });
    }


}
}

创建内核并添加激活策略

var kernel=new StandardKernel(new CommonMajiicNinjectModule());
kernel.Components.Add<IActivationStrategy, WindowsFormsStrategy>();

用于迭代后代控件的内核扩展

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 );
        }
    }
}
}
于 2015-11-25T23:45:52.280 回答
2

这当然是一个有趣的领域,我应该说,研究。我们已经为自己打造了一个解决方案,我们在其中以通用形式托管用户控件。

我们的通用表单不适用于 Designer。通过代码,我们将选择的用户控件动态添加到表单中。

对于其他框架,您应该查看 Microsoft Patterns & Practices 组的Prism/Composite这是一篇讨论 WinForms 扩展的文章。

于 2009-08-15T11:00:59.147 回答
1

我最近创建了一些UserControls需要依赖注入的可重用。由于IoC Container不用于创建那些UserControls,显然他不能自动注入依赖项。

我的解决方案是,至少启用属性注入的基类。不支持构造函数注入,因为使用无参数构造函数来创建这些实例。

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);
    }
}

要让它工作,您需要设置内核一次。通常这是在您的program.cs(WinForms) 或App.xaml.cs(WPF)中的某个地方

IocKernel = new StandardKernel(); // typically a static member
NinjectUserControl.Kernel = IocKernel;
IocKernel.Load(new Module()); // loading modules
// .. Create MainForm or whatever

要使用,只需继承NinjectUserControl然后让内核通过属性注入注入您的依赖项:

[Inject]
public IService Service { private get; set; }

请注意,这些依赖项在构造函数中是不可访问的。

于 2017-08-18T07:11:30.627 回答