2012-06-06 132 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甚至刪除/交換它的可能性。