2015-08-31 85 views
3

我想在必須向GUI控件注入資源的場景中使用依賴注入。因爲這可能是錯誤的地方,我有一些理由在這裏做,而不是在視圖模型(例如,我需要窗口句柄等)。如何使用簡單注入器依賴的WPF控件

構造函數參數注入似乎是首選方法。正如大多數人所知,WPF控件必須具有無參數的構造函數,否則XAML不起作用,對於當前場景,我喜歡保留XAML,因爲它包含一些名稱註冊和綁定。

所以:如何在WPF + XAML場景中使用構造函數-DI(如果可能的話使用Simple Injector)?

是否存在標記擴展或者是否可以將XAML解析器製作爲容器感知並接受具有參數的構造函數作爲控件?

方案例如:

<Grid> 
<gg:WhateverResourceNeedingViewer ItemSource={Binding Items}/> 
</Grid> 

和:

public class WhateverResourceNeedingViewer : ItemsControl 
{ 
    public WhateverResourceNeedingViewer(Dep1 d, DepResource d2) 
    { 
    ... 
    } 
... 
} 
+1

請參閱集成指南[這裏](https://simpleinjector.readthedocs.org/en/latest/wpfintegration.html) – qujck

+0

我看到了。但它解決了我的意圖嗎?其實我有第二個窗口我想填充。但是由於我無法從XAML實例化控件,我是否必須放棄我的XAML? (因爲缺少0-ctor) – Robetto

+0

你有一些不工作的代碼,或者這是一個理論問題嗎? – qujck

回答

4

這是很好的做法,不僅使用SOLID設計原則,建立你的ViewModels,但要做到這一點在你的意見也。 usercontrols的使用可以幫助你做到這一點。

如果技術上可行,建議方法的缺點是該設計將違反SRPOCP

SRP,因爲您的用戶控件需要的所有依賴項必須注入消費窗口/視圖中,而此視圖可能不需要(全部)這些依賴項。

而OCP因爲每一個你添加或刪除你的用戶控件的依賴,你還需要添加或從消費窗口/視圖中刪除它。

有了你能組成的觀點,就像您撰寫的其他類,如服務,命令 - 和queryhandlers等。當涉及到依賴注入的地方構成您的應用程序用戶控件是composition root

WPF中的ContentControls都是關於從應用程序中的其他「內容」'構成'你的觀點。

Caliburn Micro這樣的MVVM工具通常使用contentcontrols通過它自己的viewmodel注入一個usercontrol視圖(讀取:無代碼的xaml)。事實上,在使用MVVM時,您應該從usercontrols類構建應用程序中的所有視圖,這是最佳做法。

這可能是這個樣子:

public interface IViewModel<T> { } 

public class MainViewModel : IViewModel<Someclass> 
{ 
    public MainViewModel(IViewModel<SomeOtherClass> userControlViewModel) 
    { 
     this.UserControlViewModel = userControlViewModel; 
    } 

    public IViewModel<SomeOtherClass> UserControlViewModel { get; private set; } 
} 

public class UserControlViewModel : IViewModel<SomeOtherClass> 
{ 
    private readonly ISomeService someDependency; 

    public UserControlViewModel(ISomeService someDependency) 
    { 
     this.someDependency = someDependency; 
    } 
} 

而XAML爲的MainView:

// MainView 
<UserControl x:Class="WpfUserControlTest.MainView" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Grid> 
     <ContentControl Name="UserControlViewModel" /> 
    </Grid> 
</UserControl> 

// UserControl View 
<UserControl x:Class="WpfUserControlTest.UserControlView" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 
    <Grid> 
     <TextBlock Text="SomeInformation"/> 
    </Grid> 
</UserControl> 

其結果將是,該MainView顯示在一個窗口,在該窗口的DataContext設置爲MainViewModel。內容控件將填充UserControlView,其DataContext設置爲UserControlViewModel類。這會自動發生,因爲MVVM工具將使用Convention over configuration將視圖模型綁定到相應的視圖。

如果您不使用MVVM工具,而是直接將您的依賴關係注入窗口類的代碼後面,則可以使用相同的模式。在視圖中使用ContentControl,就像上面的例子一樣,並在窗口的構造函數中注入UserControl(帶有一個包含所需參數的構造函數)。然後,只需將ContentControl的Content屬性設置爲UserControl的注入實例。

這將是這樣的:

public partial class MainWindow : Window 
{ 
    public MainWindow(YourUserControl userControl) 
    { 
     InitializeComponent(); 
     // assuming you have a contentcontrol named 'UserControlViewModel' 
     this.UserControlViewModel.Content = userControl; 
    } 

    // other code... 
} 
+1

只要給Ric的優秀答案添加一條小評論,我已經使用注入到「MainWindows」(僅限於內容控件的shell,而不是用戶控件)的用戶控件獲得了極大的成功。內容控制允許注入幾乎任何東西,但通過分離問題來分離「這個用戶控件只做這個或那個」,並添加多個控件,甚至可以連接到另一個用戶控件中,這樣您就可以選擇和選擇零件想要在基於用戶交互的運行時使用。棱鏡做到了這一點。用戶控件是用於視圖DI的優秀容器。 –

+1

@johnpeters這正是我使用用戶控件的方式以及實現我的答案的結果,以充分發揮其能力。使用caliburn和簡單的注入器,您甚至可以將開放的通用「UserControlViewModel」與運行時綁定的單一或關閉的通用特定視圖一起注入。可能性幾乎是無止境的。 –

+0

這是一個很好的帖子,它基本上使我的問題得到回答。基本上我所期望的 - 仍然存在,仍然是希望。但是你說的是ContentControl是在UI端進行組合的實際鉤子。我已經看到了這一點,現在看來,我認爲這是一條路。然而我的問題仍然沒有解決,因爲我的問題類型的濫用WPF。我使用WinFormsHost和一個自己的,更受限制的對象層次結構。所以ContentControl是不可能的,同時WPF-DC邊界也適用。好像我不得不放棄我在那裏的XAML方法。 – Robetto