【问题标题】:How to Use Dependency Injection on UserControls & Forms如何在用户控件和表单中使用依赖注入
【发布时间】:2014-03-05 09:32:45
【问题描述】:

遇到知识鸿沟,离开 WinForms 这么久了,不确定我是否为温莎城堡正确地做这件事。

在过去的 5 年里,我一直在开发 ASP.Net 应用程序(WebForms、MVC 等)。我现在有一个项目,其中 Web 界面还不是一个可行的解决方案。所以我们用 WinForms 来做。

使用 Asp.Net,我只需设置 Castle Windsor Container、CWC、静态类,一切都将自行处理依赖注入等。

我在使用 WinForms 时遇到了一些问题。我显然无法实现与 WebForms 开发相同的依赖注入规则。

当前实施:

程序.cs:

static void Main () {
    Initialize();

    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault( false );

    var form = CWC.Resolve<frmMain>();
    Application.Run( form );

}

public static void Initialize ( string log4netPath = null ) {
    var container = new WindsorContainer();

    container.Kernel.ComponentModelCreated += ( s => {
        if ( s.LifestyleType == LifestyleType.Undefined )
            s.LifestyleType = LifestyleType.PerWebRequest;
    } );

    container.Install(
        new CoreManagerInstaller() , 
        new DomainInstaller() ,
        new RepositoryInstaller() ,
        new ServiceInstaller()
    );

    //Installer for MVC framework -- Must be done after other installers on its own.
    container.Install( new AppInstaller() );

    if ( log4netPath != null ) {
        //container.AddFacility( new LoggingFacility( LoggerImplementation.Log4net , log4netPath ) );
    }

    CWC.Init( container );
}

AppInstaller:

public class AppInstaller : IWindsorInstaller {

    #region IWindsorInstaller Members

    public void Install ( IWindsorContainer container , IConfigurationStore store ) {
        container.Register(
            Classes.FromThisAssembly()
                .BasedOn<CIMForm>().LifestyleTransient() ,
            Classes.FromThisAssembly()
                .BasedOn<CIMTabControl>().LifestyleTransient() ,
            Classes.FromThisAssembly()
                .BasedOn<CIMTabPage>().LifestyleTransient() ,
            Classes.FromThisAssembly()
                .BasedOn<UserControl>().LifestyleTransient() );
    }

    #endregion
}

以上所有内容都不是新的或有问题的atm。

问题子项是我试图从其他库中引用接口的 UserControl。在 WebForms 中,我会删除属性签名并开始在我需要的事件/方法中使用它。

这样:

public partial class ClientInformationControl : UserControl {
        public IServerRepository ServerRepository { get; set; }

        private void ClientInformation_Load ( object sender , EventArgs e ) {
            var servers = ServerRepository.Find().Select( s => new { Key=s.Id , Value=s.Name } );
            cboServers.Items.AddRange( servers.ToArray() );

        }
}

但是ServerRepository 在这个设计中永远不会被实例化。我必须手动致电CWC.Resolve&lt;IServerRepository&gt;(),以便该物业获得所需的信息。

有没有办法让 ServerRepository 自动(神奇地)填充来自容器的对象数据?

尝试执行public ClientInformationControl(IServerRepository serverRepo){},但赋值并没有持续通过构造函数,因此当触发 Control.Load 事件时,ServerRepository 属性已被清空。

【问题讨论】:

  • I now have a project where a web interface is not a viable solution, yet. So we are doing it with WinForms. - 只是一个旁注。不建议将 winforms 用于任何新项目。它是一种非常古老的技术,已被更现代、可扩展、可定制、更快、独立于分辨率、基于矢量、硬件加速、美观、基于 XAML 的技术所取代(这些技术也更接近于 Web 范式而不是winforms,并启用更清晰的模式)。你真的应该重新考虑你的决定。我无意用此评论冒犯任何人。
  • 感谢您的非建设性评论。在各种框架中这样做是有原因的,而这恰好是他们的基础架构需要并且可以处理的原因。

标签: winforms dependency-injection castle-windsor


【解决方案1】:

用户控件的问题在于它们无法被 DI 框架 (DIF) 解决。

你还没有发布你的 winform 的代码,但我假设设计器代码看起来像这样:

private void InitializeComponent()
{
    this.ClientInformationControl1 = new ClientInformationControl();
    [...]
}

这是因为您可能将用户控件拖到窗体上,因此 DIF 不知道。

有多种方法可以解决这个问题:

1:不要使用设计器添加用户控件,而是注册它们,让 DIF 为您解析它们。您可以通过将它们添加到构造函数参数、作为属性来做到这一点,或者在需要时解析用户控件。

2:给被解析的父级(表单)一个 IServerRepository 依赖项。但是你必须手动将 IServerRepository 连接到用户控件中......

【讨论】:

  • 我还没有达到清除设计器代码的状态,只使用我需要的设计器代码。由于我的其他 DLL 项目包含一个安装程序,所以我不必做一个庞大的 DIF 注册表,是否有一种更简单的方法来执行此“自动注册表”?在 MVC 中,我做了类似container.Register( Classes.FromThisAssembly().BasedOn&lt;IController&gt;().LifestyleTransient()); 的操作来让所有控制器都用于 Resolve。 WinForms会有类似的方法吗?
  • 好吧,您仍然可以使用Classes.FromThisAssembly() 注册所有内容。我相信 System.Windows.Controls.Control 固有的所有用户控件,因此您可以基于此注册它们。问题在于,在 MVC 中,控制器按约定由 ControllerFactory 工厂解决。 Winforms 没有这样的东西。
  • 因此,如果我有一个用于这些控件的派生控件类,我可以执行类似于 IController 的操作,对吗?假设应用程序中使用的所有控件都继承了IAppControl,或者AppControl 用于公共属性值。那么我的 DIF 注册表将是 Classes.FromThisAssembly().BasedOn&lt;IAppControl&gt;,还是类的等价物?
  • 是的,基本上。这就是为什么我提到我认为所有用户控件都来自System.Windows.Controls.Control,所以你可以尝试使用它。但是,即使您注册了它们,也不能像往常一样将它们拖放到表单上,因为这只会创建对象的新实例,而不是解析它。
  • 感谢您的教育和帮助。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-01
  • 2018-12-04
相关资源
最近更新 更多