Prism 6.3:以不同的视图模型重用视图

时间:2018-09-12 15:53:23

标签: wpf prism

我正在使用一个具有两个完全独立的视图模型的视图。

例如,您可以考虑使用通用列表视图在某处显示苹果,而在其他地方显示汽车。没关系。

在Xamarin的Prism.Forms中,无法使用这样的viewModel粘合视图。

 Container.RegisterTypeForNavigation<PageA, ViewModelA>("PageA1");
 Container.RegisterTypeForNavigation<PageA, ViewModelB>("PageA2");

我找不到Prism WPF中的等效项,有人可以帮助我吗?

1 个答案:

答案 0 :(得分:1)

@AdamVincent发布的链接和“ missing”方法对于使用ViewModelLocationProvider进行常规视图/视图模型导航非常有用。但是,当试图将两个视图模型用于同一个视图时,它们将不起作用。这是因为在扩展方法内部,有一个调用将视图模型注册到视图中,以供ViewModelLocationProvider使用。

private static IUnityContainer RegisterTypeForNavigationWithViewModel<TViewModel>(this IUnityContainer container, Type viewType, string name)
{
    if (string.IsNullOrWhiteSpace(name))
        name = viewType.Name;

    ViewModelLocationProvider.Register(viewType.ToString(), typeof(TViewModel));

    return container.RegisterTypeForNavigation(viewType, name);
}

在内部,ViewModelLocationProvider.Register使用字典来存储视图模型和视图之间的关联。这意味着,当您将两个视图模型注册到同一视图时,第二个将覆盖第一个。

Container.RegisterTypeForNavigation<PageA, ViewModelA>("PageA1");
Container.RegisterTypeForNavigation<PageA, ViewModelB>("PageA2");

因此,使用上述方法,在使用ViewModelLocationProvider时,它将始终创建ViewModelB的实例,因为它是最后一个要注册的实例。

此外,下一行调用RegisterTypeForNavigation,该行本身最终调用Container.RegisterType,仅传递viewType。

为解决此问题,我使用Injection属性处理了另一种方式。我有以下方法将视图模型绑定到视图

private void BindViewModelToView<TView,TViewModel>(string name)
{
    if (!Container.IsRegistered<TViewModel>())
    {
        Container.RegisterType<TViewModel>();
    }

    Container.RegisterType<TView, TViewModel>(name,new InjectionProperty("DataContext", new ResolvedParameter<TViewModel>()));
}

我们知道每个视图都将具有DataContext属性,因此Injection属性将把视图模型直接注入到该视图的DataContect中。

注册视图模型时,可以使用以下调用来代替使用RegisterTypeForNavigation:

BindViewModelToView<PageA,ViewModelA>("ViewModelA");
BindViewModelToView<PageA,ViewModelB>("ViewModelB");

要创建视图,我已经有一种方法可以用来将适当的视图注入到我的区域中,并且可以使用viewname作为键来获取正确的viewmodel实例。

private object LoadViewIntoRegion<TViewType>(IRegion region, string name)
{
    object view = region.GetView(name);
    if (view == null)
    {
        view = _container.Resolve<TViewType>(name);     
        if (view is null)
        {
            view = _container.Resolve<TViewType>();
        }
        region.Add(view, name);
    }
    return view;
}

我只是打电话给

var view = LoadViewintoRegion<PageA>(region,"ViewModelA");

var view = LoadViewintoRegion<PageA>(region,"ViewModelB");

因此,对于普通的单个View / Viewmodel,我使用ViewModelLocationProvider.AutoWireViewModel属性,在有多个ViewModel的地方,我使用这种替代方法。