从视图模型访问查看(Accessing View from Viewmodel)

2019-09-18 16:27发布

我知道这是很糟糕的设计,但我需要访问从我的视图模型视图。 这是因为我有一些旧的控制,例如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势必收集工具的一个项目,这是我喜欢的类型NavigationViewModel的视图模型。

我没有问题,例如一个TextBox绑定到我的视图模型的属性。 但我不知道我可以从我的NavigationViewModel获取到tvext访问:为了填补它TreeViewExtended模板内控制。

TIA迈克尔

Answer 1:

我建议你不访问从您的视图模型控制的WinForms。 记住,涉及该视图的视图的一切。 你可以做到这一点,如下所示:

  1. 创建一个WPF自定义控件,如命名TreeViewExtendedWrapper 。 (请参阅本文中的一个简短的教程如何创建自定义WPF控件)。

  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控件属性自定义控制。

  4. 同时添加依赖属性到您的自定义控制,你需要绑定到视图模型的所有命令。

  5. 编写C#代码的自定义控件的代码隐藏里面自定义控件的依赖属性连接属性,事件,以及控制的WinForms的方法。

  6. 内部数据模板,放在任何必要的数据绑定您的自定义控制:

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

通过这种方法,您可以使用数据绑定连接视图模型和WinForms控制,即不违反MVVM原则。



Answer 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;
     }


Answer 3:

在创建视图模型的事件,只是订阅在您看来这些事件,让查看和视图模型仍然不强耦合,你会得到你想要的。



文章来源: Accessing View from Viewmodel