c# - 如何在让 Designer 满意的同时将依赖注入(inject)应用于 UserControl View ?

标签 c# dependency-injection user-controls ninject windows-forms-designer

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

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

我不使用事件(但如果它能解决我的问题我愿意),所以我的 View 类如下所示:

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

它构建表单,构建演示者,然后将演示者注入(inject)到演示者属性中。一切都很美好。 (除了那个单例范围的演示者——有没有想过更好的方法来做到这一点?也许只是手动将演示者注入(inject)到演示者的构造函数内的 View 的 Presenter 属性中:this.view.Presenter = this)。

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

1) 不要使用 UserControls 而只使用一个实现这些多个 View 的巨大表单 (eww);

2) 将 UserControls 注入(inject)我的表单并失去对设计器的支持;

3) 您的解决方案! :)

最佳答案

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

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

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

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

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

关于c# - 如何在让 Designer 满意的同时将依赖注入(inject)应用于 UserControl View ?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1278773/

相关文章:

java - Dagger 2 : How to inject Map<Class<? extends Foo>, Provider<?扩展 Foo>>

visual-studio-2008 - Web 应用程序未获取对 ASP 命名空间的引用

C# 通用用户控件 WPF

c# - MVC 5 - 缓解 BREACH 漏洞

c# - 为什么没有引发我在 C# 中的自定义事件?

c# - 查找 PostgreSQL 数据库列中可用的最小数字

c# - 将 XAML 图像保存到 Metro 应用程序中的文件中

c# - 安全地对IoC/DI配置进行广泛的更改

angularjs - 如何注入(inject)模块并使其可供应用程序的所有模块和子模块访问(出现未知提供者错误)

c# - 在 xaml 中编写嵌套类型时出现设计时错误