【问题标题】:Multiple viewmodel interacting with each other多个视图模型相互交互
【发布时间】:2012-06-06 08:25:59
【问题描述】:

我正在开发一个 Surface WPF 项目,我们尝试在其中实现 MVVM 模式。在这个项目中,我们正在构建一些我们绑定到不同视图模型的自定义控件。

例如,我们有一个设置控件,它有一个设置视图模型,我们有一个主视图模型,它是“整体”视图模型。

在我们的 surfacewindows.xaml 页面中,我们使用 mvvm-light 中的视图模型定位器将数据上下文设置为主视图模型。此外,在我们的 surfacewindow.xaml 中,我们添加了设置控件,并在控件上将 datacontext 设置为设置视图模型。

现在我们需要两个视图模型相互交互:当前的情况是我们需要设置设置控件的可见性。我们在主视图模型上有一个布尔值 (IsSettingsControlVisible) 属性,它通过使用转换器将布尔值转换为可见性对象来绑定到控件的 Visibility 属性。

当我们需要通过单击设置控件上的关闭按钮将可见性设置为不可见时,问题就出现了。因为我们已经将控件上的数据上下文设置为设置视图模型,所以我们无法访问主视图模型。

到目前为止,我们所想到的是将设置视图模型作为属性添加到主视图模型,并从设置控件中删除数据上下文。在设置控件中,我们将使用绑定作为 SettingsProperty.Property。比我们也可以从设置控件访问主视图模型。那有意义吗?有没有更好的方法来进行此类交互?

我真的很想听听您关于如何实现这些互动的想法。

【问题讨论】:

    标签: wpf mvvm mvvm-light view-model-pattern


    【解决方案1】:

    我倾向于使用使用 Castle Windsor 构建的视图模型图。顶层视图模型使用构造函数注入来接收它需要的下一层视图模型。在视图中,我将内容呈现器绑定到视图模型上的属性以创建相应的视图图。

    这样做,父子视图模型之间的通信很容易,但同级或更远的视图模型之间的通信就有点困难了。

    在这些情况下,我倾向于使用事件聚合器或 Messenger 来允许视图模型进行通信。

    【讨论】:

    • 我会去温莎城堡看看,看看能不能帮到我。据我了解,您在“主”视图模型上使用“子”视图模型的属性进行通信。
    • 没错。所以我的整个视图模型图是独立于视图创建的。然后我可以选择以使视图模型易于通信的方式构建图形,或者我会使用 MVVM-Light 的 Messenger 类,这对你来说可能是一个更好的选择。
    • mvvm messenger 对我们来说似乎是完美的解决方案。会试一试的。
    【解决方案2】:

    由于您已经在使用 MVVMLight,我建议您使用 MVVM Light 工具包 Messenger 系统。它用于 ViewModel 之间的消息交换。 背后的概念是Mediator pattern,不同的对象在不知道彼此的情况下交换信息。

    这是一个例子:

    在 SettingsViewModel 中注册一个告诉显示设置对话框的事件

    public SettingsViewModel()
    {
      Messenger.Default.Register<ShowSettingsMessage>(this, ShowSettingsDialog);
    }
    
    private void ShowSettingsDialog(ShowSettingsMessage showSettingsMessage)
    {
      // Set the visibility:
      this.IsVisible = showSettingsMessage.Content;
    }
    

    在您的 MainViewModel 中,您发送通知,并包含在 Message 中:

    // make the settings visible, e.g. the button click command:    
    Messenger.Default.Send(new ShowSettingsMessage(true));
    

    这是消息:

    // the message:
    public class ShowSettingsMessage : GenericMessage<bool>
       {
         public ShowSettingsMessage(bool isVisible)
           : base(isVisible)
         {  }
       }
    

    我不建议将 SettingsViewModel 设为 Mainviewmodel 的属性,因为您无法在不同的上下文中使用 SettingsViewModel 甚至删除/交换它。

    【讨论】:

      【解决方案3】:

      尝试在 Settings 控件上创建一个名为 IsSettingControlVisible 的依赖属性,并将其与父 viewModel 绑定。

      编辑:

      public partial class UserControl1 : UserControl
          {
              public UserControl1()
              {
                  InitializeComponent();
              }
      
      
              public int MyProperty
              {
                  get { return (int)GetValue(MyPropertyProperty); }
                  set { SetValue(MyPropertyProperty, value); }
              }
      
              // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
              public static readonly DependencyProperty MyPropertyProperty =
                  DependencyProperty.Register("MyProperty", typeof(int), typeof(UserControl1), new UIPropertyMetadata(0));
          }
      

      并像这样使用它......

       <Window x:Class="WpfApplication1.MainWindow"
                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                  xmlns:local="clr-namespace:WpfApplication1"
                  Title="MainWindow" Height="350" Width="525">
              <Grid>
                  <local:UserControl1 MyProperty="{Binding Path=ParentViewModelProperty, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}" />
              </Grid>
          </Window>
      

      【讨论】:

      • 你会怎么做?我只能将我的控制数据上下文设置为一个视图模型。还是您建议将设置视图模型添加到主视图模型?
      • 我已经更新了我的答案。您可以使用 DependencyPropertyChanged 事件来处理您的场景。
      猜你喜欢
      • 1970-01-01
      • 2013-06-07
      • 1970-01-01
      • 1970-01-01
      • 2012-12-30
      • 1970-01-01
      • 2021-04-11
      • 2015-10-10
      • 1970-01-01
      相关资源
      最近更新 更多