简单注入器 属性 在用户控件 Windows 表单中注入

Simple Injector Property Injection in User Control Windows Forms

我必须创建一个使用 windows 表单的小应用程序。我想使用 Simple Injector 作为 IoC 容器。

简单注入器的文档写道:

It is not possible to use Constructor Injection in User Controls. User Controls are required to have a default constructor. Instead, pass on dependencies to your User Controls using Property Injection.

我已按照说明进行操作,我的程序如下所示:

internal static class Program
{
    [STAThread]
    private static void Main()
    {
        App.EnableVisualStyles();
        App.SetCompatibleTextRenderingDefault(false);
        App.Run(Bootstrap().GetInstance<FormMain>());
    }

    private static Container Bootstrap()
    {
        var container = new Container();

        container.Options.PropertySelectionBehavior =
            new ImportPropertySelectionBehavior();

        ConfigureServices(container);

        AutoRegisterWindowsForms<Form>(container);
        AutoRegisterWindowsForms<UserControl>(container);

        container.Verify();

        return container;
    }

    private static void ConfigureServices(Container container)
    {
        container.RegisterSingleton<IFormOpener, FormOpener>();
        container.RegisterSingleton<IUserService, UserService>();
        container.RegisterSingleton<IDatabaseService, DatabaseService>();
    }

    private static void AutoRegisterWindowsForms<T>(Container container)
        where T: ContainerControl
    {
        var types = container.GetTypesToRegister<T>(typeof(Program).Assembly);

        foreach (var type in types)
        {
            var registration =
                Lifestyle.Transient.CreateRegistration(type, container);

            registration.SuppressDiagnosticWarning(
                DiagnosticType.DisposableTransientComponent,
                "Forms should be disposed by app code; not by the container.");

            container.AddRegistration(type, registration);
        }
    }

我的问题是在使用拖放设计UI时,用户控件是使用new运算符自动生成的,而属性注入不起作用。我不想将容器直接注入到用户控件的GetInstance的窗体中,因为它是一种反模式,窗体设计也行不通。有什么办法可以解决这个问题吗?谢谢大家

编辑 我用我的方式解决了这个问题。我创建了一个包含 GetService 方法的静态 class,如下所示:

public static class ServiceFactory
{
    public static Container container;

    public static TService GetService<TService>() where TService: class
    {
        return container.GetInstance<TService>();
    }

}

容器需要在程序初始化时赋值:

private static Container Bootstrap()
{
    var container = new Container();

    ServiceFactory.container = container;

    ConfigureServices(container);

    AutoRegisterWindowsForms<Form>(container);
    AutoRegisterWindowsForms<UserControl>(container);

    container.Verify();

    return container;
}

然后我将服务注入用户控件如下:

private readonly IDatabaseService _databaseService;

public CustomUserControl()
{
    InitializeComponent();
    _databaseService = ServiceFactory.GetService<IDatabaseService>();
}

My problem is when using drag and drop to design UI, the user control is automatically generated using the new operator, and property injection doesn't work.

这正是文档提到 属性 注入的原因。 属性 注入允许应用于外部创建的实例(因为用户控件是由 UI 框架而不是 DI 容器创建的)。

然而,文档没有提到的是如何初始化具有依赖关系的已创建实例。为此,Simple Injector 包含一个 InitializeInstance。以下代码允许初始化使用 explicit property injection:

的用户控件
private static Container container;

public static void InitializeControl(UserControl control)
{
    var producer = container.GetRegistration(control.GetType(), true);
    producer.Registration.InitializeInstance(control);
}

不幸的是,这远非完美,因为它需要窗体和用户控件依赖于 DI 容器。为防止这种情况,您可以改为通过 Method Injection 将依赖项从包含表单传递到用户控件,但这样做的缺点是您很容易必须传递许多依赖项,从而导致使用表单的构造函数爆炸。

或者,与文档所述相反,可以从 DI 容器解析用户控件并使用设计器来规避 here by Ron. This might have consequences,但是,我没有这方面的经验.