继承/组件化在WPF视图

本文关键字:WPF 视图 组件 继承 | 更新日期: 2023-09-27 18:10:58

假设我的WPF应用程序中有几个视图,它们都显示一个报告,但每个视图显示不同的报告。
我创建了一个基本ViewModel,它包含所有报告共有的所有东西。每个报表视图都有自己的ViewModel,该ViewModel派生自基ViewModel。这些派生的viewmodel有以下职责:

  1. 生成报告数据
  2. 将报表数据格式化打印
  3. 为报告参数提供属性
  4. 为可以在生成的报告上执行的其他操作提供命令(可选)

这些都很好,很简洁,但是,视图完全是一团糟。基本上,每个视图都是相同的,只有一些小的变化,例如:

  1. 为报告参数提供不同的控制
  2. 为附加操作提供绑定到命令的按钮

我想实现以下目标:

  1. 有一个基本视图,定义所有报告视图共有的所有东西,类似于一个站点。掌握ASP.NET。这将包含搜索按钮、打印按钮、显示报告的网格等。
  2. 有具体的视图-每个报告一个-只定义搜索参数的控件和附加操作的按钮

如何做到这一点?在谷歌上搜索WPF母版页面,会出现很多定制的解决方案——肯定有一个标准的方法吧?

继承/组件化在WPF视图

在WPF中,如果Content被设置为相同的DataType实例,则占位符ContentControl.ContentTemplate可以根据其DataTemplate.DataType自动设置。

http://www.japf.fr/2009/03/thinking-with-mvvm-data-templates-contentcontrol/

我不确定这是创建复合视图的标准方式,但我已经成功地定义了一个包含一系列视图所需的通用控件的主视图(在我的情况下是Window),并通过使用ContentControl作为ASP中的ContentPlaceholder的等效,为每个不同的子视图注入不同的UserControl。净masterpage。在我的例子中,我定义了一个所有子视图都实现的接口:

public interface ISubView
{
   BaseViewModel ViewModel { get; set; }
}

这允许我的ApplicationController在处理显示特定视图的请求时将视图模型推入子视图。然后,子视图在显示之前通过主视图上的setter属性与主视图组合。

ApplicationController是集中打开和关闭视图任务的类;每当应用程序中的任何内容想要显示特定视图时,它都会请求ApplicationController。当它接收到显示特定视图的请求时,它会从内部"注册表"中查找并构造相应的子视图和视图模型子类,并将这些部分组合在一起。在应用程序启动时,您创建ApplicationController并注册ViewModel子类和View子类的组合。部分示例实现如下:

public class ApplicationController
{
   private IDictionary<string, Tuple<Func<ISubView>, Func<BaseViewModel>> _registry;
   private Func<IShellWindow> _shellActivator;
   public ApplicationController(Func<IShellWindow> shellActivator)
   {
      _registry = new Dictionary<string, Tuple<Func<ISubView>, Func<BaseViewModel>>();
      _shellActivator = shellActivator;
   }
   public void RequestShow(string viewName)
   {
      var shell = _shellActivator(); 
      var viewToModel = _registry[viewName];
      var view = viewToModel.Item1();
      var viewModel = viewToModel.Item2();
      view.ViewModel = viewModel;
      shell.Display(view);
   }
   public Register(string name, Func<ISubView> subViewCreator, Func<ViewModel> viewModelCreator)
   {
      _registry.Add(name, new Tuple(subViewCreator, viewModelCreator));
   }
}

在shell的Display方法(在IShellView接口上定义)中,您可以这样做:

   public void Display(ISubView view)
   {
      contentHolder.Content = view;
      DataContext = view.ViewModel;
      Show();
   }

应用程序启动将包括如下内容:

var appController = new ApplicationController(() => new ShellWindow());
appController.Register("EmployeesReport", () => new EmployeesReportView(), () => new EmployeesReportViewModel);
appController.Register("OrdersReport", () => new OrdersReportView(), () => new OrdersReportViewModel());
//etc.