多个视图模型相互交互

时间:2012-06-06 08:25:59

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

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

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

在我们的surfacewindows.xaml页面中,我们使用mvvm-light中的viewmodel定位器将datacontext设置为主视图模型。同样在我们的surfacewindow.xaml上,我们添加了我们的设置控件,在控件上我们将datacontext设置为settings viewmodel。

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

当我们需要通过单击设置控件上的关闭按钮将可见性设置为不可见时,问题就出现了。因为我们已将控件上的datacontext设置为settings viewmodel,所以我们无法访问mainviewmodel。

我们到目前为止所考虑的是将设置viewmodel作为属性添加到mainviewmodel并从settings控件中删除datacontext。在settingscontrol中,我们将使用绑定作为SettingsProperty.Property。我们也可以从setupss控件访问mainviewmodel。那有意义吗?是否有更好的方式进行这种互动?

我非常想听听您关于如何进行这些互动的想法。

3 个答案:

答案 0 :(得分:1)

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

这样做,父子视图模型很容易进行通信,但兄弟或更远的视图模型更难沟通。

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

答案 1 :(得分:1)

由于您已经在使用MVVMLight,我建议使用MVVM Light工具包Messenger系统。它用于ViewModels之间的消息交换。 背后的概念是Mediator pattern,其中不同的对象在不相互了解的情况下交换信息。

以下是一个例子:

在SettingsViewModel寄存器中指向一个告诉显示设置对话框的事件

public SettingsViewModel()
{
  Messenger.Default.Register<ShowSettingsMessage>(this, ShowSettingsDialog);
}

private void ShowSettingsDialog(ShowSettingsMessage showSettingsMessage)
{
  // Set the visibility:
  this.IsVisible = showSettingsMessage.Content;
}

在MainViewModel中,您发送通知,包含在消息:

// 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,甚至删除/交换它。

答案 2 :(得分:0)

尝试在名为IsSettingControlVisible的Settings控件上创建一个Dependency属性,并将其与父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>