2012-06-06 61 views
1

我正在处理一个Surface WPF项目,我们尝试实现MVVM模式。在这个项目中,我们正在构建一些我们绑定到不同视图模型的自定义控件。多个viewmodel互相交互

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

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

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

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

我们到目前为止想过的是将设置viewmodel作为属性添加到mainviewmodel并从设置控件中删除datacontext。在settingscontrol中,我们将使用作为SettingsProperty.Property的绑定。我们也可以从设置控制中访问主视图模型。那有意义吗?有没有更好的方式来进行这种交互?

我真的很想听听你如何让这些互动发生的想法。

回答

1

我倾向于与使用温莎城堡构建视图模型的图表工作。顶级视图模型使用构造函数注入来接收它需要的下一级视图模型。在视图中,我将内容演示者绑定到视图模型上的属性以创建相应的视图图形。

这样做,父级子视图模型可以很容易地进行通信,但是对于兄弟或更远距离的视图模型来说,交流起来有点困难。

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

+0

我会看看温莎城堡,看看能不能帮助我。正如我所理解的,你正确地使用了“main”视图模型上的“sub”viewmodel来进行通信。 – ChristiaanV

+1

没错。所以我的整个视图模型图独立于视图创建。我有选择然后构建图表的方式,以便视图模型可以很容易沟通,或者我会使用MVVM-Light的Messenger类,这对您来说可能更好。 – Tim

+0

mvvm使者看起来像是我们完美的解决方案。会试一试。 – ChristiaanV

0

尝试在设置控件上创建一个名为IsSettingControlVisible的依赖项属性,并将其与父视图模型绑定。

编辑:

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> 
+0

你会怎么做?我只能将我的控件datacontext设置为一个viewmodel。还是你建议将设置viewmodel添加到主视图模型? – ChristiaanV

+0

我已经更新了我的答案。您可以使用DependencyPropertyChanged事件来处理您的方案。 –

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甚至删除/交换它的可能性。