ReactiveTabbedPage数据绑定

Gar*_*cis 5 reactiveui xamarin.forms

我一直在使用ReamaUI与Xamarin Forms一段时间,但在尝试使用ReactiveTabbedPage时,我遇到了一堵砖墙.我无法弄清楚ViewModel将如何绑定到ReactiveTabbedPage的子级ReactiveContentPage.

因此,作为一个例子,我可能有以下XAML:

<ReactiveTabbedPage x:Name="TabbedPage">
    <local:Page1View x:Name="Page1" />
    <local:Page2View x:Name="Page2" />
</ReactiveTabbedPage>
Run Code Online (Sandbox Code Playgroud)

其中Page1View和Page2View都是ReactiveContentPage类型,T是关联的ViewModel.

我期望发生的是,当ReactiveTabbedPage被导航到时,将显示Page1View,并且将加载ViewModel(就像我直接导航到Page1View时那样).但是,ViewModel永远不会被调用(构造函数永远不会被触发,也不会发生数据绑定).

但是,Page1View和Page2View都会渲染,我可以看到在这些视图中创建的初始数据(例如标签的默认文本等).

我知道ViewModel的工作正常,因为如果我直接导​​航到Page1View(例如不在ReactiveTabbedPage中),所有内容都会按照我的预期显示.

我错过了什么,或者我错误地做了什么?或者这在当前版本的RxUI中是否不受支持?

任何意见是极大的赞赏!

Ken*_*art 8

将VM绑定到子页面的责任在于主页(即ReactiveTabbedPage).它只知道哪个VM对应哪个视图.

让我们一步一步迈出这一步.首先,MainViewModel:

public class MainViewModel : ReactiveObject
{
    public ChildViewModel1 Child1 => new ChildViewModel1();

    public ChildViewModel2 Child2 => new ChildViewModel2();
}
Run Code Online (Sandbox Code Playgroud)

这段代码显然不太现实,因为您不希望在每次访问属性时重新创建子VM.它更像是与此相关的API.

ChildViewModel1 看起来像这样:

public class ChildViewModel1 : ReactiveObject
{
    public string Test => "Hello";
}
Run Code Online (Sandbox Code Playgroud)

而且ChildViewModel2看起来大同小异.

现在我们可以开始设置视图了.我们MainView.xaml看起来像这样:

<?xml version="1.0" encoding="utf-8" ?>
<rxui:ReactiveTabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:TypeArguments="vms:MainViewModel"
             xmlns:local="clr-namespace:ReactiveTabbedPageTest"
             xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
             xmlns:vms="clr-namespace:ReactiveTabbedPageTest.VMs"
             x:Class="ReactiveTabbedPageTest.MainView">

    <local:Child1View x:Name="child1View" Title="Child 1"/>
    <local:Child2View x:Name="child2View" Title="Child 2"/>

</rxui:ReactiveTabbedPage>
Run Code Online (Sandbox Code Playgroud)

请注意,它声明了每个子视图.我们需要将VM连接到那些视图,我们在代码隐藏中执行以下操作MainView:

public partial class MainView : ReactiveTabbedPage<VMs.MainViewModel>
{
    public MainView()
    {
        InitializeComponent();
        this.ViewModel = new VMs.MainViewModel();

        this.WhenActivated(
            disposables =>
            {
                this
                    .OneWayBind(this.ViewModel, x => x.Child1, x => x.child1View.ViewModel)
                    .DisposeWith(disposables);
                this
                    .OneWayBind(this.ViewModel, x => x.Child2, x => x.child2View.ViewModel)
                    .DisposeWith(disposables);
            });
    }
}
Run Code Online (Sandbox Code Playgroud)

我通过使用WhenActivatedOneWayBind调用这是最安全的方式.实际上,你的子VM不太可能会改变,所以直接分配它们而不是绑定是完全没问题的.

现在我们的孩子视图可以被抛在一起了.这是ChildView1.xaml:

<?xml version="1.0" encoding="utf-8" ?>
<rxui:ReactiveContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="ReactiveTabbedPageTest.Child1View"
             x:TypeArguments="vms:ChildViewModel1"
             xmlns:rxui="clr-namespace:ReactiveUI.XamForms;assembly=ReactiveUI.XamForms"
             xmlns:vms="clr-namespace:ReactiveTabbedPageTest.VMs">
    <Label x:Name="label" VerticalTextAlignment="Center" HorizontalTextAlignment="Center"/>
</rxui:ReactiveContentPage>
Run Code Online (Sandbox Code Playgroud)

代码隐藏:

public partial class Child1View : ReactiveContentPage<ChildViewModel1>
{
    public Child1View()
    {
        InitializeComponent();

        this.WhenActivated(
            disposables =>
            {
                this
                    .OneWayBind(this.ViewModel, x => x.Test, x => x.label.Text)
                    .DisposeWith(disposables);
            });
    }
}
Run Code Online (Sandbox Code Playgroud)

我们再次使用通常的RxUI绑定优势来将VM中的属性与UI中的控件相关联.再次,您可以针对不变异的属性进行优化.

出于这个例子的目的,它们ChildView2大致相同ChildView1,但显然它可能完全不同.

最终结果如你所料:

反应标签控制的动画

屏幕截图中没有明显的内容,但非常重要的是当您切换它时,每个选项卡都会停用(如果它实现的话,它的关联视图模型也是如此ISupportsActivation).这意味着您可以在不使用时清除该选项卡的任何绑定和订阅,从而减少内存压力并提高性能.