【问题标题】:How to connect multiple ViewModels to a single View with Prism's viewlocator?如何使用 Prism 的视图定位器将多个 ViewModel 连接到单个视图?
【发布时间】:2016-03-29 13:24:24
【问题描述】:

我使用 Prism 的 viewlocator 来连接 View 和 ViewModel,我遵循约定,将 View 放在 view 文件夹中,将 ViewModel 放在 viewmodel 文件夹中,并在 viewmodel 类的名称中添加后缀 viewmodel。一切正常。我只是想知道如何将多个视图模型连接到一个视图?

例如,我有:

查看:CustomerView 在 XAML 中我只是使用:prism:ViewModelLocator.AutoWireViewModel="True"

查看视频:CustomerViewModel

现在我想添加CustomerViewModel2,但它不起作用,因为它与视图的名称不匹配

【问题讨论】:

  • 你想达到什么目的?一个视图只有一个DataContext 属性,所以它只能有一个视图模型。当然,子视图甚至视图的一部分可以有不同的视图模型,但这不能使用 PRISM 的视图模型定位器来完成。您必须为此使用数据模板或查看注入/区域。
  • 我的 ViewModel 类变得太大而且令人困惑,所以我想将它拆分成更多的 ViewModel,类似于 Models。
  • 这听起来可能是重构代码的好时机。将一些代码移到其他有意义的类中可以减少一些混乱。至少,使用区域对代码进行分组,以便您可以在需要时折叠/展开它。

标签: c# wpf xaml mvvm prism


【解决方案1】:

正如我在评论中提到的,不可能将单个视图与多个(同一级别)视图模型直接连接起来。

您必须将您的视图拆分为一个主视图和(多个)子视图(在 XAML 中逻辑上或通过将子视图移动到单独的 UserControls 中物理上)。

这是我的建议。

  1. 使用 PRISM 区域。

定义一个包含区域的主视图:

<Window>
    <StackPanel Orientation="Vertical">
        <ContentControl prism:RegionManager.RegionName="Region1"/>
        <ContentControl prism:RegionManager.RegionName="Region2"/>
    </StackPanel>
</Window>

创建将“插入”(在 PRISM 的术语中 - 注入)到您的主视图中的子视图:

<UserControl x:Class="UserControl1">
    <Grid/>
</UserControl>

<UserControl x:Class="UserControl2">
    <Grid/>
</UserControl>

最后,您必须在 PRISM 中注册您的视图,以便实例化它们:

// Obtain the region manager over DI
IRegionManager regionManager;
regionManager.RegisterViewWithRegion("Region1", typeof(UserControl1));
regionManager.RegisterViewWithRegion("Region2", typeof(UserControl2));

每个子视图都有自己的视图模型。您可以使用 PRISM 的视图模型定位器来自动连接它们。

  1. 使用数据模板。

你的主视图:

<Window>
<Window.Resources>
    <DataTemplate DataType="vm:ViewModel1">
        <v:UserControl1/>
    </DataTemplate>
    <DataTemplate DataType="vm:ViewModel2">
        <v:UserControl2/>
    </DataTemplate>
</Window.Resources>
    <ItemsControl ItemsSource="{Binding Items}"/>
</Window>

将子视图模型添加到您的主视图模型的Items 集合中,WPF 将为您创建视图并自动连接视图模型。

class MasterViewModel : BindableBase
{
    public IEnumerable<BindableBase> Items
    {
        get { return new[] { new ViewModel1(), new ViewModel2() }
    }
}

当然,您可以使用 DI 来实例化您的视图模型。

  1. 使用“堆叠”视图模型。

类似这样的:

class MainViewModel : BindableBase
{
    public ViewModel1 ViewModel1 { get; private set; }
    public ViewModel2 ViewModel2 { get; private set; }
}

在您的主视图中,您必须相应地设置绑定。

<Window>
    <StackPanel>
        <TextBlock Text="{Binding ViewModel1.SomeValue}"/>
        <TextBox Text="{Binding ViewModel2.SomeValue}"/>
    </StackPanel>
</Window>

【讨论】:

  • 感谢您的详细回答。我真的很喜欢区域的想法,我记得我以前尝试过使用它。问题是,我正在使用的视图是我导航到的页面。所以如果我这样做:'regionManager.RegisterViewWithRegion("Region1", typeof(UserControl1));'然后一旦应用程序启动,这个视图(页面)就会变得可见。我目前使用'RegisterForNavigation'方法,但这种与'RegisterViewWithRegion'冲突
【解决方案2】:

您可以将子视图模型作为页面主视图模型的属性公开,然后在绑定中为子视图模型的路径添加属性名称的前缀。

【讨论】:

    【解决方案3】:

    将您的视图模型设置为分部类。

    【讨论】:

    • 从技术上讲,这个答案是不正确的,因为部分类定义虽然描述了一个类 - 只会实例化一个对象。虽然这看起来像是 OP 的解决方案,但总的来说,它不是一个。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-23
    • 2012-03-06
    相关资源
    最近更新 更多