带 Xamarin.Forms 的棱镜 - 如何自动装配另一个 ContentView 内的 ContentView

Prism with Xamarin.Forms - how to autowire ContentView which is inside another ContentView

当 ContentView 直接包含在页面中时,我们成功地将 ContentView 连接到它们的 ViewModel,使用 XAML 如:

<local:AwesomeView mvvm:ViewModelLocator.AutowirePartialView=”{x:Reference self}” />

其中 self 是父页面。

但是,我们有包含 ContentView 的 ContentView,并且如上所述对嵌套视图使用 AutoWirePartialView 不起作用。 ContentViews 没有连接到他们的 ViewModels。

查看 Prism 代码:​​

  1. AutoWirePartialView 有评论 "This API is Obsolete and will 在 8.0 预览期间被删除
  2. 属性 更改了 AutoWirePartialView 的处理程序明确检查父级是否为 Page,因此不能与父级 ContentView
  3. 一起使用

所以从 Prism 代码中可以很清楚地看出为什么这行不通!

有没有办法用 Prism 实现这一点?

版本: Xamarin.Forms - 4.4.0.991265

棱镜 - 7.1.0.431

我的意见是,为了保持整洁,使用默认的棱镜方法并将视图模型仅绑定到相应的页面,而不绑定到任何子视图。

任何到页面内组件的绑定都应该通过页面视图模型上的属性进行,这样无论内容视图在显示层次结构中的深度如何,您都可以实现绑定。

例如:

您页面的视图模型

public class PageAViewModel : ViewModelBase
{
   public ContentViewAViewModel ContentViewViewModel
   {
      get { return _contentViewViewModel; }
      set { SetProperty(ref _contentViewViewModel, value); }
   }
}

您的页面浏览量

<?xml version="1.0" encoding="UTF-8"?>
<views:BasePage xmlns="http://xamarin.com/schemas/2014/forms"
                xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                xmlns:components="clr-YourProject.Components"
                xmlns:views="clr-YourProject.Views"
                x:Class="YourProject.Views.PageA">
     <Grid RowSpacing="0">
          <Grid RowSpacing="0">
                <components:ContentViewA BindingContext="{Binding ContentViewViewModel}"/>
          </Grid>
    </Grid>
</views:BasePage>

部分视图确实已过时。它过时的原因是我们将 Region support 引入 Prism 8。在我们为 Prism.Forms 实施区域之前,部分视图总是作为一种快速和临时的解决方案来帮助弥合差距。区域更强大,可以让你做更多的事情,比如嵌套和延迟加载视图。

实际上你拥有的嵌套区域的概念:

ComponentViewA which has its own ViewModel.

Then you have ComponentViewB which has it's own ViewModel and has ComponentViewA as a child

And ComponentViewA is itself a child of AwesomePage

这听起来像是您希望支持的一般概念。所以简短的回答是,在 Prism 7 中没有这样做的好方法。肯定有一些技巧,例如您可以将页面作为参数传递并在后面的代码中设置 属性,例如:

public class ComponentViewB : ContentView
{
    public static readonly BindableProperty ParentPageProperty =
        BindableProperty.Create(nameof(ParentPage), typeof(Page), typeof(ComponentViewB), null, propertyChanged: OnParentPageChanged);

    private static void OnParentPageChanged(BindableObject bindable, object oldValue, object newValue)
    {
        // This guards the action from being performed more than once.
        if(oldValue is null && newValue != null && bindable is ComponentViewB view)
        {
            // This assumes you've set the property x:Name="componentViewA"
            // for your ComponentViewA in XAML
            ViewModelLocator.SetAutowirePartialView(view.componentViewA, (view.ParentPage);
        }
    }

    public Page ParentPage
    {
        get => (Page)GetValue(ParentPageProperty);
        set => SetValue(ParentPageProperty, value);
    }
}

老实说,如果我今天必须做点什么,我会推荐这样做。一旦我们合并了我在上面引用的 PR,我会建议您更新到预览并迁移到使用区域。