简体   繁体   English

如何在WPF应用程序中捆绑View,ViewModel和DataTemplate以便于重用?

[英]How to bundle View, ViewModel and DataTemplate in a WPF application for easy reuse?

Situation: 情况:

I'd like to create a flexible application which is ViewModel driven. 我想创建一个由ViewModel驱动的灵活应用程序。

The basic flow is like this: 基本流程如下:

  1. Design the main ViewModel 设计主ViewModel
  2. Create a UserControl as View and a DataTemplate for the main ViewModel to select this View 创建UserControl作为View,并为主ViewModel创建DataTemplate以选择此View
  3. If there are sub components, the are modelled by sub ViewModels 如果有子组件,则由子ViewModels建模
  4. Create a UserControl as View and a DataTemplate for the sub ViewModel to select this View 创建UserControl作为View,并为子ViewModel创建DataTemplate以选择此View

If a sub view model needs to be presented, it is done via a DataTemplate. 如果需要显示子视图模型,则通过DataTemplate完成。

This approach can also be seen here (option 8). 这种方法也可以在这里看到(选项8)。

So the main window xaml looks something like this: 所以主窗口xaml看起来像这样:

<Window>
    <!-- somehow I need to add the mapping from ViewModel to View -->
    <Grid>
        <!-- the main ViewModel -->
        <ContentPresenter Content="{Binding Path=Content}"/>
    </Grid>
</Window>

The Content property might contain a view model that contains a list of elements named Children and it's associated DataTemplate might look like this: The children are also flexibly rendered by a suitable DataTemplate. Content属性可能包含一个视图模型,其中包含名为Children的元素列表,并且它的关联DataTemplate可能如下所示:子项也由适当的DataTemplate灵活地呈现。

<UserControl>
    <Grid>
        <StackPanel>
            <!-- display the child ViewModels  in a list -->
            <ItemsControl ItemsSource="{Binding Path=Children}" />
         </StackPanel>
    </Grid>
</UserControl>

Question: 题:

  1. How should I organize the ViewModels, Views and their DataTemplates so I don't need to hardwire them in the MainWindow? 我应该如何组织ViewModel,Views及其DataTemplates,以便我不需要在MainWindow中对它们进行硬连线?

  2. How do I then connect this to the main window? 如何将其连接到主窗口?

  3. It would be nice if it is stub-able, ie I can see the result during design time with a design time dataContext. 如果它是可存根的,那将是很好的,即我可以在设计时使用设计时dataContext查看结果。

Basically I want to bundle the View, ViewModel and DataTemplate and be able to use them in an application that doesn't need to know about the details (eg some sub ViewModel implements a certain interface and is injected into the main ViewModel). 基本上我想捆绑View,ViewModel和DataTemplate,并且能够在不需要了解细节的应用程序中使用它们(例如,一些子ViewModel实现某个接口并注入到主ViewModel中)。

Have you looked into Prism . 你看过棱镜吗?

The framework allows you to define regions within your UI that views can be registered against. 该框架允许您在UI中定义可以注册视图的区域。 I believe this answers your 2nd question (2). 我相信这回答了你的第二个问题(2)。

xmlns:cal="http://www.codeplex.com/prism"

<Window>
   <!-- somehow I need to add the mapping from ViewModel to View -->
   <Grid>
      <!-- the main ViewModel -->
      <ContentPresenter cal:RegionManager.RegionName="MainRegion"/>
   </Grid>
</Window>

For your first question (1) we structure our entities in the following way: 对于您的第一个问题(1),我们按以下方式构建实体:

View - we have an abstract base class that looks similar too: 视图 - 我们有一个看起来相似的抽象基类:

public abstract class ViewBase<T> : UserControl, IView<T> where T: IViewModel
{
    public T ViewModel
    {
        get
        {
            return this.viewModel;
        }
        protected set
        {
            this.viewModel = value;

            this.DataContext = this.viewModel;
        }
    }

    public ViewBase(IUnityContainer container)
    {
        this.ViewModel = container.Resolve<T>();
    }
}

This then allows us to create Views in xaml using the following: 这允许我们使用以下方法在xaml中创建视图:

<ui:ViewBase x:Class="MyView"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:ui="NAMESPACE FOR VIEWBASE"
         xmlns:vm="NAMESPACE FOR VIEWMODEL"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         x:TypeArguments="vm:MYVIEWMODEL">

In the code behind of a View we do the following: 在View背后的代码中,我们执行以下操作:

public partial class MyView : ViewBase<IMyViewModel>

This then makes use of the constructor in the base class to resolve the ViewModel and set it to it's DataContext. 然后,它使用基类中的构造函数来解析ViewModel并将其设置为它的DataContext。

This then allows you to design your view (3) as you intended and also removes the need for having a DataTemplate. 然后,您可以按预期设计视图(3),并且无需使用DataTemplate。

Using the UnityContainer we then register the views as follows: 然后使用UnityContainer注册视图,如下所示:

this.container.RegisterType<IMyView, MyView>();
this.container.RegisterType<IMyViewModel, MyViewModel>();

this.regionManager.RegisterViewWithRegion("MainRegion", typeof(IMyView));

Note that "MainRegion" here matches the RegionName specified in the MainWindow xaml. 请注意,此处的“MainRegion”与MainWindow xaml中指定的RegionName匹配。 You can expand this further to use a TabControl if you wanted to display multiple views in the same area, or even break your MainWindow down into different regions. 如果要在同一区域中显示多个视图,或者甚至将MainWindow分解为不同的区域,可以进一步扩展它以使用TabControl。

I hope this helps. 我希望这有帮助。

1) You can in each view add DataTemplates in UserControl.Resources, ie 1)您可以在每个视图中添加UserControl.Resources中的DataTemplates,即

<UserControl.Resources>
    <DataTemplate DataType="{x:Type viewmodels:Customer1ViewModel}">
       <views:Customer1View/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type viewmodels:Customer2ViewModel}">
       <views:Customer2View/>
    </DataTemplate>
</UserControl.Resources>

Now you defined for each ViewModel appropriate View. 现在您为每个ViewModel定义了相应的View。 You put only data templates for ViewModels that you expect in that View, ie children's ViewModels 您只为该视图中的ViewModel添加了数据模板,即子视图模型

2) Hm, your MainWindow also has to have a ViewModel, ie put in MainWindow DataContext an instance of MainWindows's ViewModel. 2)嗯,你的MainWindow也必须有一个ViewModel,即在MainWindow DataContext中放入一个MainWindows的ViewModel实例。 That ViewModel has to contain the property Content (in which you put ViewModel for content). ViewModel必须包含属性Content(在其中放置ViewModel作为内容)。 You can do that manually in App.xaml.cs 您可以在App.xaml.cs中手动执行此操作

public partial class App : Application
{

    public App()
    {
        this.Startup += App_Startup;
    }

    public void App_Startup(object sender, StartupEventArgs e)
    {

        this.MainWindow = new MainWindow();

        //create view model and set data context
        MainWindowViewModel vm = new MainWindowViewModel();
        this.MainWindow.DataContext = vm;

        //show window
        this.MainWindow.ShowDialog(vm);
    }
}

3) I'm not sure about this, you probably will not be able to see results in design time. 3)我不确定这一点,你可能无法在设计时看到结果。

I'm not sure if I'm fully understanding what exactly you want, if this doesn't help, please replay to this answer with further explanation. 我不确定我是否完全理解你想要什么,如果这没有帮助,请重播这个答案并进一步解释。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM