2017-01-10 41 views
2

我一直在Xamarin Forms中使用ReactiveUI一段時間,但是當嘗試使用ReactiveTabbedPage時我碰到了一堵磚牆。我無法弄清楚ViewModel如何綁定到ReactiveTabbedPage的子節點ReactiveContentPage。ReactiveTabbedPage數據綁定

所以,作爲一個例子,我可能有以下XAML:

<ReactiveTabbedPage x:Name="TabbedPage"> 
    <local:Page1View x:Name="Page1" /> 
    <local:Page2View x:Name="Page2" /> 
</ReactiveTabbedPage> 

凡Page1View和Page2View的類型ReactiveContentPage的兩個T是相關聯的視圖模型。

我想要發生的事情是,當ReactiveTabbedPage被導航到時,Page1View將被顯示,並且ViewModel將被加載(以與如果我直接導​​航到Page1View相同的方式)。但是,ViewModel永遠不會被調用(構造函數永遠不會被觸發,也不會發生數據綁定)。

但是,Page1View和Page2View都會呈現,並且我可以看到在這些視圖中創建的初始數據(例如,標籤的默認文本等)。

我知道ViewModel的東西工作正常,因爲如果我直接導​​航到Page1View(例如不在ReactiveTabbedPage),所有東西都會按照我的預期顯示。

我錯過了什麼,或者我會以錯誤的方式回答這個問題嗎?或者這只是在當前版本的RxUI中不支持?

任何意見非常感謝!

回答

5

將VM綁定到子頁面的責任在於主頁(即ReactiveTabbedPage)。只有它知道哪個VM對應於哪個視圖。

讓我們一步一個腳印吧。首先,在MainViewModel

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

    public ChildViewModel2 Child2 => new ChildViewModel2(); 
} 

這顯然代碼是不現實的,因爲你不會希望在每次屬性訪問重新孩子的VM。它更適合這裏的API。

ChildViewModel1看起來是這樣的:

public class ChildViewModel1 : ReactiveObject 
{ 
    public string Test => "Hello"; 
} 

而且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> 

注意它聲明瞭每個子視圖。我們需要虛擬機掛接到這些意見,這是我們在代碼隱藏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); 
      }); 
    } 
} 

我用WhenActivatedOneWayBind調用來完成這個最安全的方式。實際上,你的子虛擬機不太可能會改變,所以直接分配而不是綁定是完全沒問題的。

現在我們的孩子的意見可以扔在一起。下面是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> 

和代碼隱藏:

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); 
      }); 
    } 
} 

再次我們正在做平常RxUI結合善良的VM屬性與UI控件相關聯。再一次,你可以優化這個不變異的屬性。

就本例而言,ChildView2ChildView1大致相同,但顯然它可能完全不同。

最終的結果是你所期望的:

animation of reactive tabbed control

什麼也不明顯從截圖,但很重要的是,每個選項卡被取消當你從它切換出來(如將其相關的查看模型,如果它實施了ISupportsActivation)。這意味着您可以清除該選項卡未使用時的任何綁定和訂閱,從而減少內存壓力並提高性能。

+0

這並不明顯,但完美地解決了這個問題!關於停用的好消息呢! –