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

本文关键字:视图 模型 包含 ListView 绑定 ReactiveList | 更新日期: 2023-09-27 18:15:21

我有一个ParentViewModel,它包含ChildViewModelsReactiveList。我想将它绑定到一个ListView,它将显示ChildViewsChildView将一些文本绑定到Label,并根据状态enum设置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绑定到ChildList ListView

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简单的UserControlImageLabel

<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方式做到这一点。我错过了什么?

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

我认为你需要在你的ChildViewModel中完全设置你的属性,以便它们在你的ChildView可以订阅的ViewModel中引发更改。查看ViewModels文档

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