2012-06-28 110 views
2

我知道這是糟糕的設計,但我需要從我的viewmodel訪問視圖。這是因爲我有一些舊的控件,例如Winforms控件,不支持綁定,需要用代碼填充。從Viewmodel訪問視圖

我使用的AvalonDock 2.0 MVVM模型,並有一些與此類似:

<ad:DockingManager x:Name="dockManager" 
        DocumentsSource="{Binding Files}" 
        AnchorablesSource="{Binding Tools}" 
     ActiveContent="{Binding ActiveDocument, Mode=TwoWay, Converter={StaticResource ActiveDocumentConverter}}"> 
     <ad:DockingManager.LayoutItemTemplateSelector> 
      <local:PanesTemplateSelector> 
       <local:PanesTemplateSelector.NavigationViewTemplate> 
        <DataTemplate> 
         <tvext:TreeViewExtended /> 
        </DataTemplate> 
       </local:PanesTemplateSelector.NavigationViewTemplate> 
      </local:PanesTemplateSelector> 
     </ad:DockingManager.LayoutItemTemplateSelector> 

所以模板NavigationViewTemplate勢必收集工具的一個項目,這是我喜歡的類型NavigationViewModel的視圖模型。

我沒有問題綁定例如一個TextBox到我的viewmodel的屬性。但我不知道如何從我的NavigationViewModel訪問模板中的tvext:TreeViewExtended控件以填充它。

TIA Michael

+1

不要害怕在你的代碼中加入一些額外的代碼來達到這個目的。如果你想分享你的視圖模型與不同的用戶界面,這樣做會很難做到這一點。您的視圖模型爲UI提供服務,但不應直接依賴特定的UI組件。 –

回答

3

我建議您不要從ViewModel訪問Winforms控件。在視圖中保留與視圖相關的所有內容。您可以這樣做:

  1. 創建一個WPF自定義控件,例如,名爲TreeViewExtendedWrapper。 (有關如何創建自定義WPF控件的簡短教程,請參見this article)。

  2. 裏面的自定義控件的控件模板(在主題\ Generic.xaml文件),將您的WinForms控制:

    <ControlTemplate TargetType="{x:Type local:TreeViewExtendedWrapper}"> 
        <Border Background="{TemplateBinding Background}" 
         BorderBrush="{TemplateBinding BorderBrush}" 
         BorderThickness="{TemplateBinding BorderThickness}"> 
         <tvext:TreeViewExtended /> 
        </Border> 
    </ControlTemplate> 
    
  3. 添加依賴屬性爲所有的WinForms控件屬性的自定義控件你需要綁定到ViewModel。

  4. 還需要爲您的自定義控件添加依賴屬性,以獲取需要綁定到視圖模型的所有命令。

  5. 在自定義控件的代碼隱藏內部編寫C#代碼,以將自定義控件的依賴項屬性連接到Winforms控件的屬性,事件和方法。

  6. 內,您的數據模板,放在任何必要的數據綁定自定義控件:

    <DataTemplate> 
        <local:TreeViewExtendedWrapper MyProperty={Binding MyProperty}/> 
    </DataTemplate> 
    

通過這種方法,您可以使用數據綁定連接視圖模型和WinForms控制,即你不違反MVVM原則。

+0

我正在嘗試你的方法。但是,因爲我從來沒有寫過一個自定義的WPF控件,你能告訴我,我如何在TreeViewExtendedWrapper中爲DataContextChanged建立一個處理程序? – MTR

+0

你可以使用方法'DependencyProperty.OverrideMetadata()'來做到這一點。 [本文](http://social.msdn.microsoft.com/Forums/da/wpf/thread/ec84ee14-fc8b-465c-88ce-7b38cfabc5ee)包含一些示例代碼,演示如何在DataContext屬性更改時通知。 – 2012-06-29 07:20:03

+0

本文中的示例不起作用,出現錯誤消息CS0123:Keine高級「OnDataContextChanged」stimmt代碼「System.Windows.PropertyChangedCallback」代碼被拒絕。 – MTR

2

是啊,我不是讓視圖模型瞭解視圖的大風扇,但既然你問,這裏有一個想法:

1. Create an interface for your View (if you haven't already) and add whatever functionality to that interface that you need access to from the ViewModel. Lets call it ISomeView 
2. add/implement the interface on the View 
3. add property to the ViewModel ISomeView View {get;set;} 
4. in the view depending where the ViewModel is being injected assign populate the ViewModel's property, for example you can do it on DataContextChanged: 

    private void OnDataContextChanged (object sender, ...EventArgs e) 
    { 
     // making up your ViewModel's name as ISomeViewModel 
     ((ISomeViewModel)sender).View = this; 
    } 
3

創建您的視圖模型活動,只是訂閱這些事件在您的視圖,所以視圖和視圖模型仍然沒有很強的耦合,你得到你想要的。

+0

+1這是要走的路。 – Tilak