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

相關問題