两个用户控件之间的 WPF MVVM 通信 [英] WPF MVVM Communication Between Two User Controls

查看:33
本文介绍了两个用户控件之间的 WPF MVVM 通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am working on a WPF application that consists of a lot of data entry forms. I have exposed each of these forms as a separate user control. So, I have CustomerView (UserControl), CompaniesView (UserControl). Each form consist of fields like Customer Name, Company Name that user enters and then saves them.

使用由保存"、删除"和关闭"选项组成的工具栏执行保存操作.我已将 Toolbar 创建到一个单独的 UserControl 中,并将其放在容器视图/外壳视图中.以下是可以清楚说明的事物的结构.

The save action is performed using a Toolbar which consists of "Save", "Delete" and "Close" options. I have created Toolbar into a separate UserControl and put that in the container view/ shell view. Here is the structure of things that will make it clear.

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

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


Data Entry forms are injected here on the fly


______________________________________


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

问题是,当我单击工具栏中的保存"按钮时,我对包含表单的视图一无所知.我需要获取附加到该视图的 MVVM 模型,以便我可以保存它.

The problem is that when I click the Save button in the Toolbar I have no idea of knowing anything about the view which contains the form. I need to get hold of the MVVM model attached to that view so I can save it.

推荐答案

我使用 UserControls 处理这个问题的方式是我的 shell 视图模型将同时引用 ToolbarViewModel 和 DataEntryViewModel.工具栏将有一个为每个可能的命令触发的事件,外壳视图模型将适当地处理该事件.下面是一个例子:

The way I handle this with UserControls is my shell view model will have a reference to both the ToolbarViewModel and the DataEntryViewModel. The Toolbar will have an event that fires for each of the possible commands and the shell view model will handle the event appropriately. Here is an example:

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

In the MainView, I create a DataTemplate for each of the possible DataEntry views/viewmodels. Then bind a ContentPresenter to a property in my MainViewModel of a base type for the DataEntryViewModel's.

<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 方法.

The DataEntryViewModel will have a method for all the different possible actions that the toolbar may want to execute on them. I have only provided the Save method here for brevity sake.

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 对每个可以执行的命令都有一个事件.

The ToolbarViewModel has an event for each of the commands that can be executed.

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 时,我为 Toolbar 公开的每个命令事件注册一个方法.在事件处理程序中,我为事件调用 DataEntryContext 的适当方法.

The MainViewModel has a property for the Toolbar's DataContext and one for the DataEntry DataContext. When assigning the ToolbarContext, I register a method for each command event that the Toolbar exposes. In the eventhandler, I call the appropriate method of the DataEntryContext for the event.

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();
   }
}

这篇关于两个用户控件之间的 WPF MVVM 通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆