如何将视图模型的 ReactiveList 绑定到包含视图模型视图的 ListView

How to bind a ReactiveList of view models to a ListView containing Views of the view model

我有一个 ParentViewModel,其中包含 ReactiveListChildViewModels。我想将它绑定到将显示 ChildViewsListViewChildView 将一些文本绑定到 Label 并根据状态枚举设置 Image 资源:

ParentViewModel.cs ChildViewModels

的简单容器
public class ParentViewModel : ReactiveObject
{
    public ReactiveList<ChildViewModel> Children { get; }
        = new ReactiveList<ChildViewModel>();
}

ChildViewModel.cs 有一些文字和 Status

public class ChildViewModel : ReactiveObject
{
    public string SomeText { get; set; }

    public enum Status
    {
        Unknown,
        Known
    }

    public Status CurrentStatus { get; set; } = Status.Unknown;
}

ParentView.xaml UserControl 包装 ListView,使用 ChildView 作为数据模板。我确保在 DataTemplate.

上添加了 ViewModel="{Binding}"
<UserControl x:Class="MyProject.UI.ParentView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:vm="clr-namespace:MyProject.View_Models"
        xmlns:ui="clr-namespace:MyProject.UI">
    <ListView x:Name="ChildList" BorderThickness="0">
        <ListView.ItemTemplate>
            <DataTemplate>
            <!--I have also tried the following line, didn't work  -->
            <!--<DataTemplate DataType="{x:Type vm:ChildViewModel}">-->
                <ui:ChildView ViewModel="{Binding}"/>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>
</UserControl>

ParentView.xaml.cs 为其 ParentViewModel 创建依赖项 属性,并将视图模型的 Children 绑定到子列表列表视图

public partial class ParentView : UserControl, IViewFor<ParentViewModel>
{
    public static readonly DependencyProperty ViewModelProperty
        = DependencyProperty.Register(
            "ViewModel",
            typeof(ParentViewModel),
            typeof(ParentView));

    object IViewFor.ViewModel
    {
        get { return ViewModel; }
        set { ViewModel = (ParentViewModel)value; }
    }

    public ParentViewModel ViewModel
    {
        get { return (ParentViewModel )GetValue(ViewModelProperty); }
        set
        {
            SetValue(ViewModelProperty, value);
            BindToViewModel(value);
        }
    }

    private void BindToViewModel(ParentViewModel viewModel)
    {
        this.OneWayBind(viewModel, vm => vm.Children, v => v.ChildList.ItemsSource);
    }
}

ChildView.xaml 带有 ImageLabel

的简单 UserControl
<UserControl x:Class="MyProject.UI.ChildView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel Orientation="Horizontal">
        <Image Name="StatusIcon" Margin="2" />
        <Label Name="DisplayName" />
    </StackPanel>
</UserControl>

ChildView.xaml.cs 绑定 ChildViewModel 并设置图像数据

public partial class ChildView : UserControl, IViewFor<ChildViewModel>
{
    public static readonly DependencyProperty ViewModelProperty
        = DependencyProperty.Register(
            "ViewModel",
            typeof(ChildViewModel),
            typeof(ChildView));

    public ChildView()
    {
        InitializeComponent();
    }

    object IViewFor.ViewModel
    {
        get { return ViewModel; }
        set { ViewModel = (ChildViewModel)value; }
    }

    public ChildViewModel ViewModel
    {
        get { return (ChildViewModel )GetValue(ViewModelProperty); }
        set
        {
            SetValue(ViewModelProperty, value);
            BindToViewModel(value);
        }
    }

    private void BindToViewModel(ChildViewModel viewModel)
    {
        viewModel
            .WhenAnyValue(vm => vm.CurrentStatus)
            .Subscribe(status =>
            {
                // set StatusIcon's image based on status
            });

        this.Bind(viewModel, vm => vm.DisplayName, v => v.SomeText);
    }
}

我在 ChildView 中设置了断点以查看 ViewModel 属性是否命中,但它们从未命中。当我将 ChildViewModels 添加到 ParentVieWModel.Children 时,会创建一个 ChildView,但它从未正确绑定。我可以订阅 ChildrenCollectionChanged 事件并手动设置绑定,但我想以正确的 XAML/ReactiveUI 方式进行。我错过了什么?

我认为您需要在您的 ChildViewModel 中完全设置您的属性,以便它们引发您的 ChildView 可以订阅的 ViewModel 中的更改。参见 ViewModels documentation

string someText ;
public string SomeText {
    get { return someText; }
    set { this.RaiseAndSetIfChanged(ref someText , value); }
}

Status currentStatus;
public Status CurrentStatus {
    get { return currentStatus; }
    set { this.RaiseAndSetIfChanged(ref currentStatus, value); }
}

或者如果一个或两个都是只读的。

readonly ObservableAsPropertyHelper<string> someText;
public string SomeText{
    get { return someText.Value; }
}

readonly ObservableAsPropertyHelper<Status> currentStatus;
public Status CurrentStatus{
    get { return currentStatus.Value; }
}