3

我知道这是不好的设计,但我需要从我的视图模型访问视图。这是因为我有一些旧控件,例如 Winforms 控件,它们不支持绑定,需要由代码填充。

我正在使用 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 绑定到集合 Tools 中的一项,这是我的 NavigationViewModel 类型的 ViewModel。

我将文本框绑定到我的视图模型的属性没有问题。但我不知道如何从我的 NavigationViewModel 访问模板内的 tvext:TreeViewExtended 控件以填充它。

TIA 迈克尔

4

3 回答 3

7

是的,我不是让 ViewModel 知道视图的忠实粉丝,但是既然你问了,这里有一个想法:

 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;
     }
于 2012-06-28T15:33:20.367 回答
4

在您的视图模型中创建事件并在您的视图中订阅这些事件,因此视图和视图模型仍然不是强耦合并且您得到您想要的。

于 2012-06-29T05:47:48.250 回答
3

I suggest that you do not access the Winforms control from your ViewModel. Keep everything that relates to the view in the view. You can do this as follows:

  1. Create a WPF custom control, e.g. named TreeViewExtendedWrapper. (See this article for a short tutorial how to create custom WPF controls).

  2. Inside the control template of the custom control (in the Themes\Generic.xaml file), place your Winforms control:

    <ControlTemplate TargetType="{x:Type local:TreeViewExtendedWrapper}">
        <Border Background="{TemplateBinding Background}"
            BorderBrush="{TemplateBinding BorderBrush}"
            BorderThickness="{TemplateBinding BorderThickness}">
            <tvext:TreeViewExtended />
        </Border>
    </ControlTemplate>
    
  3. Add dependency properties to your custom control for all Winforms control properties that you need to bind to the ViewModel.

  4. Also add dependency properties to your custom control for all commands that you need to bind to the view model.

  5. Write C# code inside the code-behind of the custom control to connect the dependency properties of your custom control to the properties, events, and methods of the Winforms control.

  6. Inside your data template, place your custom control with any necessary data bindings:

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

With this approach, you can use data binding to connect ViewModel and Winforms control, i.e. you do not violate MVVM principles.

于 2012-06-28T14:41:06.473 回答