4

我不得不重新编写一个大的WinForms应用程序,我想使用MVC来增加测试功能等。我还想将Ninject作为IoC容器来使用是轻量级的,速度很快,并且会增加我的应用程序的可扩展性。构建一个使用MVC和Ninject作为IoC容器的WinForms应用程序

我已经做了大量的阅读,并且我已经成功地开始了这个新应用程序的开发。但是,我不确定在使用Ninject时我有正确的想法。该代码...

与Program.cs文件和相关类开始...

static class Program 
{ 
    [STAThread] 
    static void Main() 
    { 
     FileLogHandler fileLogHandler = new FileLogHandler(Utils.GetLogFilePath()); 
     Log.LogHandler = fileLogHandler; 
     Log.Trace("Program.Main(): Logging initialized"); 

     CompositionRoot.Initialize(new ApplicationModule()); 

     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false); 
     Application.Run(CompositionRoot.Resolve<ApplicationShellView>()); 
    } 
} 

public class CompositionRoot 
{ 
    private static IKernel _ninjectKernel; 

    public static void Initialize(INinjectModule module) 
    { 
     _ninjectKernel = new StandardKernel(module); 
    } 

    public static T Resolve<T>() 
    { 
     return _ninjectKernel.Get<T>(); 
    } 
} 

public class ApplicationModule : NinjectModule 
{ 
    public override void Load() 
    { 
     Bind(typeof(IApplicationShellView)).To(typeof(ApplicationShellView)); 
    } 
} 

的我ApplicationShellView

public partial class ApplicationShellView : Form, IApplicationShellView 
{ 
    public ApplicationShellView() 
    { 
     InitializeComponent(); 
    } 

    public void InitializeView() 
    { 
     dockPanel.Theme = vS2012LightTheme; 
    } 
} 

与接口

public interface IApplicationShellView 
{ 
    void InitializeView(); 
} 

的控制器这个观点是

public class ApplicationShellController 
{ 
    private IApplicationShellView view; 

    public ApplicationShellController(IApplicationShellView view) 
    { 
     view.InitializeView(); 
    } 
} 

目前该控制器是多余的,虽然此代码的工作和我的视图显示,我有一些重要问题......

  1. 我应该使用ApplicationShellController来初始化我的形式,目前这是不是使用MVC“模式”?
  2. 这感觉就像我写了一个服务定位器,并从我读到的,这是不好的。我应该如何使用Ninject for IoC来初始化我的应用程序?
  3. 任何其他建议,我正在做什么对[如果有的话!] /错?

非常感谢您的时间。

+0

我认为这个/类似的问题之前曾被问到过,特别是关于“服务定位器”。通常这个问题是/应该更多地关于如何与任何DI容器一起使用WinForms进行MVC ... – BatteryBackupUnit

+0

这不是一个通用的问题。这是一个关于具体情况的问题。你怎么能说它之前被问过?我的问题并不是专门针对服务定位器,而是如何将MVC与IOC容器相结合。 – MoonKnight

+0

您可以举个例子说明如何在没有DI的情况下在ApplicationShellView中使用其他表单或服务? (我没有体验过winforms,我应该看到生活管理)。 –

回答

2
  1. 不,你不应该初始化你的控制器,这正是IoC和Ninject的目的。当初始化你的视图/表单时,Ninject应该让视图获取它所依赖的控制器,这将自动获取它所依赖的控制器等等。
    当然这不会像你现在设置它一样。对于初学者来说,你的观点需要知道它所依赖的控制器。

    public partial class ApplicationShellView : Form, IApplicationShellView 
    { 
        private IApplicationShellController _controller; 
    
        public ApplicationShellView() 
        { 
         InitializeComponent(); 
         init(); 
    
         //InitializeView() 
        } 
    
        private void init() { 
         _controller = NinjectProgram.Kernel.Get<IApplicationShellController>(); 
         //Because your view knows the controller you can always pass himself as parameter or even use setter to inject 
         //For example: _controller.SetView1(this); 
        } 
    
        public void InitializeView() 
        { 
         dockPanel.Theme = vS2012LightTheme; 
        } 
    } 
    
    public class ApplicationShellController : IApplicationShellController 
    { 
    
        //Implementes functionality for the MainForm. 
    
        public ApplicationShellController() 
        { 
         //Also possible to add other controllers with DI 
        } 
    } 
    
  2. 这确实看起来像一个服务定位器,只需初始化您的视图应该足够。

    public class NinjectProgram 
    { 
        //Gets the inject kernal for the program. 
        public static IKernel Kernel { get; protected set; } 
    } 
    
    public class Program : NinjectProgram 
    { 
        [STAThread] 
        private static void Main() 
        { 
         Kernel = new StandardKernel(); 
         Kernel.Load(new ApplicationModule()); 
    
         Application.Run(new ApplicationShellView()); 
        } 
    } 
    
    public class ApplicationModule : NinjectModule 
    { 
        public override void Load() 
        { 
         //Here is where we define what implementations map to what interfaces. 
         Bind<IApplicationShellController>().To<ApplicationShellController>(); 
    
         //We can also load other modules this project depends on. 
         Kernel.Load(new NinjectModule()); 
        } 
    } 
    
  3. 不要试图使它过于复杂,一个好的开始是很重要的,但你可以随时申请变更的时间和地点在开发过程中需要的。

我相信下面GitHub的项目可能是一个很好的起点:Example of how you might use Ninject within a WinForms application.

如果您有任何问题,只是发表评论,我会尽力尽快

回答
+0

我现在已经掌握了Seemann的书“.NET的依赖注入”,它似乎建议使用DI Container/Composition Root,就像我上面的那样。本书建议这个CompositionRoot应该是唯一应该使用IoC容器的'Resolve'('Get' for Ninject)方法的地方。然后它建议使用“Three Calls Pattern”使用这个“CompositionRoot”,但我没有得到的是当这个模式变成“服务定位器反模式”时?从我在第一章中读到的内容看来,本书的第3部分,我们不应该在CompositionRoot之外使用内核调用。非常感谢 – MoonKnight

+0

@Killercam我同意Mark的说法,当内核在“Composition Root”之外使用时,它就成为一种反模式。我(大部分)也赞同他的看法。就个人而言,我有时会违反它,对于一些工厂来说,如果依赖关系对容器的负面影响超过将其放入组合根的好处。 – BatteryBackupUnit

+1

我对WinForms不是很熟悉,但是因为我相信@ Killercam的原始代码正在工作,所以我认为调用'_controller = NinjectProgram.Kernel.Get ();'作为服务位置和反模式在这种情况下。为什么?因为呼叫可以更靠近主要方法 - 就像Killercam的原始解决方案一样。 – BatteryBackupUnit

相关问题