关于c#:WPF视图中的继承/”组合”

Inheritance / “Componization” in WPF views

假设我的WPF应用程序中有几个视图都显示一个报表,但是每个视图都显示一个不同的报表。
我创建了一个基本的ViewModel,其中包含所有报表共有的所有内容。每个报表View都有自己的ViewModel,该ViewModel是从基本ViewModel派生的。这些派生的ViewModel具有以下职责:

  • 生成报告数据
  • 格式化报告数据以进行打印
  • 提供报告参数的属性
  • 提供可在生成的报告上执行的其他操作的命令(可选)
  • 这一切都很好而简洁,但是,Views完全是一团糟。
    基本上,每个视图都是相同的,只有一些小的更改,例如:

  • 为报告参数提供不同的控件
  • 提供绑定到命令的按钮以执行其他操作
  • 我想实现以下目标:

  • 具有一个基本视图,该基本视图定义了所有报表视图共有的所有内容,类似于ASP.NET中的Site.master。这将包含搜索按钮,打印按钮,报表在其中显示的网格等。
  • 拥有具体的视图(每个报告一个),仅定义搜索参数的控件和其他操作的按钮
  • 如何执行此操作?在WPF主页上进行谷歌搜索会带来很多定制解决方案-当然必须有一种标准方法吗?


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

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


    我不确定这是创建复合视图的标准方法,但是我已经成功定义了一个主视图(在本例中为Window),该主视图包含一个视图族所需的通用控件并通过使用ContentControl等效于ASP.NET母版页中的ContentPlaceholder,为每个不同的子视图将不同的UserControl注入到母版中。就我而言,我定义了一个所有子视图都实现的接口:

    1
    2
    3
    4
    public interface ISubView
    {
       BaseViewModel ViewModel { get; set; }
    }

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

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    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接口上定义)中,您将执行以下操作:

    1
    2
    3
    4
    5
    6
       public void Display(ISubView view)
       {
          contentHolder.Content = view;
          DataContext = view.ViewModel;
          Show();
       }

    应用程序启动中将包含以下内容:

    1
    2
    3
    4
    5
    var appController = new ApplicationController(() => new ShellWindow());
    appController.Register("EmployeesReport", () => new EmployeesReportView(), () => new EmployeesReportViewModel);
    appController.Register("OrdersReport", () => new OrdersReportView(), () => new OrdersReportViewModel());

    //etc.