如何与2个或更多ViewModel交互

时间:2013-12-03 23:44:11

标签: c# wpf mvvm listbox viewmodel

我编写了一个工具,其中ListBox绑定到ObserservableCollection<object>,并且我定义了不同的数据类型。我使用PropertyDataTemplateSelector在ListBox中显示数据。 PropertyDataTemplateSelector引用了设置为DataTemplates的多个UserControls。有一个后台类通过检查PropertyDataTemplateSelector类型然后应用正确的objectDataTemplate提供逻辑。

以下是UserControlsMainWindow的XAML缩写示例。

的UserControl1            

    <TextBlock Text="{Binding Path=Val1}"
               Style="{StaticResourse Yes}" />

    <Button Content="I'm Button 1"
            Command="{Binding Path=PathtoCommand1}"
            CommandParameter="{Binding Parameter1}"
            IsEnabled="{Binding IsEnabled1}" />

    <Button Content="I'm Button 2"
            Command="{Binding Path=PathtoCommand2}"
            CommandParameter="{Binding Parameter2}"
            IsEnabled="{Binding IsEnabled2}"
            Tag="{Binding Path="DataContext.TagItem2}">

       <Button.ContextMenu>
         <ContextMenu>
           <MenuItem IsCheckable="True"
                     IsChecked="{Binding Path=Tag}"
                     DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
         </ContextMenu>
       </Button.ContextMenu>

    </Button>
  </StackPanel>
</UserControl>

UserControlN

<UserControl x:Class="AwesomerControl">
  <StackPanel Orientation="Vertical">

    <TextBlock Text="{Binding Path=FancyName2}"
               Style="{StaticResourse Yes}" />

    <Button Content="Clicker 1"
            Command="{Binding Path=DoSomethingGreat1}"
            CommandParameter="{Binding Greatness1}"
            IsEnabled="{Binding IsTurnedOn1}" />

    <Button Content="Clicker 2"
            Command="{Binding Path=DoSomethingGreat2}"
            CommandParameter="{Binding Greaterness2}"
            IsEnabled="{Binding IsTurnedOn2}"
            Tag="{Binding Path="DataContext.TagItem2}">

       <Button.ContextMenu>
         <ContextMenu>
           <MenuItem IsCheckable="True"
                     IsChecked="{Binding Path=Tag}"
                     DataContext="{Binding Path=PlacementTarget, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
         </ContextMenu>
       </Button.ContextMenu>

    </Button>
  </StackPanel>
</UserControl>

在此,我将UserControls设置为指定的DataTemplate。移出UserControl以使XAML更易于阅读/导航。实际上,UserControls各有几百行。

<Window.Resources>
  <DataTemplate x:Key"Template1">
     <customControls:AwesomeControl/>
  </DataTemplate>
  ...
  <DataTemplate x:Key"TemplateN">
     <customControls:AwesomerControl/>
  </DataTemplate>


  <dts:PropertyDataTemplateSelector x:Key="templateselector"
                                    Template1="{StaticResource Template1"}
                                    ...
                                    TemplateN="{StaticResource TemplateN"}
</Window.Resources>

ListBox被定义为此。

<ListBox ItemSource="{Binding Path=CollectionofMyObjects}"
         ItemTemplateSelector="{StaticResource templateselector}" />

我使用一个ViewModel来推动MainWindowUserControls

所以这就是我所处的位置。我现在正在按照我的意愿工作,但是在不断努力学习(这是我的第一个MVVM / WPF / C#项目)我想继续探索如何让我的代码“更好”(不过那是定义的) 。我不打算在这里解决错误。因此,为了避免一般/广泛的问题,我会问我想知道什么。有人可以纠正我,我会适当地更新“问题”

问题:如何为每个ViewModel制作UserControlsViewModels的某些UserControls偶尔需要与MainWindow_ViewModel进行双向通信。我的问题的主要症结是弄清楚多个虚拟机将如何通信。

1 个答案:

答案 0 :(得分:1)

你很接近,但它还不是相当 MVVM。 ;)

  1. 首先,将与每个UserControl相关的所有功能分解到自己的类中。这些是您的视图模型类。
  2. 您的控件现在应该成为“视图”类,并且它们应该拥有自己的标记文件。您可以使用DataTemplate.DataType自动将视图模型类类型连接到其视图,而不是使用模板选择器。
  3. 视图模型之间有很多通信选项。为了进一步提高你的教育水平,我会考虑一个具有内置通信解决方案的轻量级MVVM框架。我个人最喜欢的是Caliburn.Micro,其中包含一个EventAggregator服务,该服务能够以松散耦合的方式将对象从一个视图模型发布到另一个视图模型。

    继续学习,你走在正确的轨道上!