两个用户控件之间的WPF MVVM通信

时间:2014-07-10 16:52:53

标签: wpf

我正在开发一个包含大量数据输入表单的WPF应用程序。我已将这些表单中的每一个作为单独的用户控件公开。所以,我有CustomerView(UserControl),CompaniesView(UserControl)。每个表单都包含用户输入的客户名称,公司名称等字段,然后保存它们。

使用工具栏执行保存操作,该工具栏包含“保存”,“删除”和“关闭”选项。我已将Toolbar创建为一个单独的UserControl,并将其放在容器视图/ shell视图中。以下是将要明确的事情结构。

CONTAINER BEGINS
--------------------------------------------------------------------

-----------------------------------
THIS IS THE TOOLBAR
----------------------------------
______________________________________


Data Entry forms are injected here on the fly


______________________________________


---------------------------------------------------------------------
CONTAINER ENDS

问题是,当我单击工具栏中的“保存”按钮时,我不知道有关包含表单的视图的任何信息。我需要掌握附加到该视图的MVVM模型,以便我可以保存它。

1 个答案:

答案 0 :(得分:0)

我使用UserControls处理这个问题的方法是我的shell视图模型将引用ToolbarViewModel和DataEntryViewModel。工具栏将有一个事件触发每个可能的命令,shell视图模型将适当地处理事件。这是一个例子:

在MainView中,我为每个可能的DataEntry视图/视图模型创建了一个DataTemplate。然后将ContentPresenter绑定到DataEntryViewModel的基本类型的MainViewModel中的属性。

<Window
   //usual window declarations>

   <Window.Resources>
      <DataTemplate DataType="{x:Type vm:DataEntryViewModel}">
         <view:DataEntryView />
      </DataTemplate>

      //more DataTemplates for other data entry views
   </Window.Resources>

   <Grid>
      <Grid.RowDefinitions>
         <RowDefinition Height="Auto" />
         <RowDefinition Height="Auto" />
      </Grid.RowDefinitions>

      <view:ToolbarView Grid.Row="0"
                        DataContext="{Binding ToolbarContext}" />
      <ContentPresenter Grid.Row="1"
                        Content="{Binding DataEntryContext}" />
   </Grid>
</Window>

DataEntryViewModel将拥有一个方法,用于工具栏可能要对其执行的所有不同操作。为了简洁起见,我在这里只提供了Save方法。

public interface IDataEntryViewModelBase
{
   void Save();
}

public abstract class DataEntryViewModelBase : ViewModelBase, IDataEntryViewModelBase
{
   public virtual void Save()
   {
      //base save work
   }
}

public class DataEntryViewModel : DataEntryViewModelBase
{
   public override void Save()
   {
      base.Save();

      //unique save work
   }
}

ToolbarViewModel为每个可执行的命令都有一个事件。

public class ToolbarViewModel : ViewModelBase, IToolbarViewModel
{
   //can just use EventArgs here if no need to pass data when this event fires
   public event EventHandler<SaveExecutedArgs> SaveExecuted;

   public ICommand CmdSave
   {
      get { return new RelayCommand(() => OnSaveExecuted()); }
   }

   protected void OnSaveExecuted()
   {
       var handler = SaveExecuted;
       if (handler == null) return;
       handler(this, new SaveExecutedArgs());
   }
}

MainViewModel具有Toolbar的DataContext属性和DataEntry DataContext的属性。分配ToolbarContext时,我为工具栏公开的每个命令事件注册一个方法。在eventhandler中,我为事件调用了DataEntryContext的适当方法。

public class MainViewModel : ViewModelBase
{
   private IToolbarViewModel _toolbarContext;
   public IToolbarViewModel ToolbarContext
   {
      get { return _toolbarContext; }
      set { Set("ToolbarContext", ref _toolbarContext, value); }
   }

   private IDataEntryViewModelBase _dataEntryContext;
   public IDataEntryViewModelBase DataEntryContext
   {
      get { return _dataEntryContext; }
      set { Set("DataEntryContext", ref _dataEntryContext, value); }
   }

   public MainViewModel()
   {
      _toolbarContext = new ToolbarViewModel();
      _toolbarContext.SaveExecuted += ToolbarContext_SaveExecuted;
      _dataEntryContext = new DataEntryViewModel();
   }

   private void ToolbarContext_SaveExecuted(object sender, SaveExecutedArgs e)
   {
       //can change this to popup a warning or however you want to handle it
       //under the circumstance that DataEntryContext is null
       if (DataEntryContext == null) return;

       DataEntryContext.Save();
   }
}