微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C# WPF 中的 ReactiveUI:绑定列表列表

如何解决C# WPF 中的 ReactiveUI:绑定列表列表

我刚开始使用 C# 中的 ReactiveUI 和 MVVM - WPF。

我创建了一个测试项目,其目标是表示对象的链表。 一个大学列表,每个大学都有一个课程列表。在课程中,考试由学生匿名提交。 我首先只显示大学列表。这有效。

但是我无法显示课程列表。我看到一个 ListBox,但条目为空。 (为了清楚起见,我暂时省略了考试的介绍。)

  1. 大学0
    • 课程 0
      • 考试 0:待定
      • 考试 1:已完成
    • 课程 1
  2. 大学1
    • 课程 3
      • 考试 4:完成
      • Exam5:完成

我假设在 Universityviewmodel.cs 中我必须以某种方式绑定课程列表,但是如何绑定?

对于初学者,我使用 ReactiveUI 页面上的示例作为指南:A Compelling Example

Appviewmodel.cs

using DynamicData;
using DynamicData.Binding;
using ReactiveUI;
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;

namespace UniversityViewer
{
    public class Appviewmodel : ReactiveObject
    {
        private readonly IDataProviderService _dataProviderService;
        public ReadOnlyObservableCollection<Universityviewmodel> Universityviewmodels { get; }

        private string _searchTerm;
        public string SearchTerm
        {
            get => _searchTerm;
            set => this.RaiseAndSetIfChanged(ref _searchTerm,value);
        }

        public Appviewmodel()
        {
            _dataProviderService = new DataProviderService();
            
            Func<University,bool> universityFilter(string text) => university =>
            {
                return
                    string.IsNullOrEmpty(text) ||
                    university.Name.ToLower().Contains(text.ToLower());
            };

            var filterPredicate = this.WhenAnyValue(x => x.SearchTerm)
                                      .Throttle(TimeSpan.FromMilliseconds(250),RxApp.TaskpoolScheduler)
                                      .distinctUntilChanged()
                                      .Select(universityFilter);

            var DataLoader = _dataProviderService.Universities
                .Connect()
                .Filter(filterPredicate)
                .Transform(university => new Universityviewmodel(university))
                .sort(SortExpressionComparer<Universityviewmodel>.Ascending(u => u.Name))
                .ObserveOn(RxApp.MainThreadScheduler)
                .Bind(out var bindingData)
                .Subscribe();

            Universityviewmodels = bindingData;
        }
    }
}

University.cs

using System.Collections.Generic;

namespace UniversityViewer
{
    public class University
    {
        public University(string name)
        {
            Name = name;
            Courses = new List<Course>()
            {
                new Course("1234"),new Course("2345"),new Course("3456")
            };
        }

        public string Name { get; set; }
        public List<Course> Courses { get; set; }
    }
}

UniversityView.xaml

<reactiveui:ReactiveUserControl
  x:Class="UniversityViewer.UniversityView"
  xmlns:universityViewer="clr-namespace:UniversityViewer"
  x:TypeArguments="universityViewer:Universityviewmodel"
  xmlns:reactiveui="http://reactiveui.net"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <Grid.RowDeFinitions>
            <RowDeFinition Height="Auto" />
            <RowDeFinition Height="Auto" />
        </Grid.RowDeFinitions>
        <TextBlock textwrapping="WrapWithOverflow" 
                 Margin="6" VerticalAlignment="Center">
          <Run FontWeight="SemiBold" x:Name="nameRun"/>
        </TextBlock>

        <ListBox x:Name="ListBoxCourses"
                 Grid.Row="1" Margin="5" HorizontalContentAlignment="Stretch"
                 ScrollViewer.HorizontalScrollBarVisibility="disabled" />
    </Grid>
</reactiveui:ReactiveUserControl>

UniversityView.xaml.cs

using ReactiveUI;
using System.Reactive.disposables;

namespace UniversityViewer
{
    public partial class UniversityView : ReactiveUserControl<Universityviewmodel>
    {
        public UniversityView()
        {
            InitializeComponent();
            this.WhenActivated(disposableRegistration =>
            {
                this.OneWayBind(viewmodel,viewmodel => viewmodel.Name,view => view.nameRun.Text)
                    .disposeWith(disposableRegistration);

                this.OneWayBind(viewmodel,viewmodel => viewmodel.Courses,view => view.ListBoxCourses.ItemsSource)
                    .disposeWith(disposableRegistration);
            });
        }
    }
}

Universityviewmodel.cs

using ReactiveUI;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace UniversityViewer
{
    public class Universityviewmodel : ReactiveObject
    {
        private University _university;
        public ReadOnlyObservableCollection<Courseviewmodel> Courseviewmodels { get; }

        public Universityviewmodel(University university)
        {
            _university = university;

            //var DataLoader = _university.Courses
            //    .Connect()
            //    ....

            //Courseviewmodels = bindingData;
        }

        public string Name => _university.Name;
        public List<Course> Courses => _university.Courses;
    }
}

Course.cs

namespace UniversityViewer
{
    public class Course
    {
        public Course(string name)
        {
            Name = name;
            //Exams = new List<Exam>();
        }

        public string Name { get; set; }
        //public List<Exam> Exams { get; set; }
    }
}

CourseView.xaml

<reactiveui:ReactiveUserControl
  x:Class="UniversityViewer.CourseView"
  xmlns:universityViewer="clr-namespace:UniversityViewer"
  x:TypeArguments="universityViewer:Courseviewmodel"
  xmlns:reactiveui="http://reactiveui.net"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <Grid>
        <Grid.RowDeFinitions>
            <RowDeFinition Height="Auto" />
            <RowDeFinition Height="Auto" />
        </Grid.RowDeFinitions>
        <TextBlock textwrapping="WrapWithOverflow" 
                 Margin="6" VerticalAlignment="Center">
          <Run FontWeight="SemiBold" x:Name="nameRun"/>
        </TextBlock>

        <!--<ListBox x:Name="ListBoxExams"
                 Grid.Row="1" Margin="5" HorizontalContentAlignment="Stretch"
                 ScrollViewer.HorizontalScrollBarVisibility="disabled" />-->
    </Grid>
</reactiveui:ReactiveUserControl>

CourseView.xaml.cs

using ReactiveUI;
using System.Reactive.disposables;

namespace UniversityViewer
{
    public partial class CourseView : ReactiveUserControl<Courseviewmodel>
    {
        public CourseView()
        {
            InitializeComponent();
            this.WhenActivated(disposableRegistration =>
            {
                this.OneWayBind(viewmodel,view => view.nameRun.Text)
                    .disposeWith(disposableRegistration);
            });
        }
    }
}

Courseviewmodel.cs

using ReactiveUI;

namespace UniversityViewer
{
    public class Courseviewmodel : ReactiveObject
    {
        private Course _course;

        public Courseviewmodel(Course course)
        {
            _course = course;
        }

        public string Name => _course.Name;
    }
}

解决方法

为了解析 UniversityViewCourseViewModels 应该绑定到 Courses 而不是 CourseView

this.OneWayBind(ViewModel,viewModel => viewModel.CourseViewModels,view => view.ListBoxCourses.ItemsSource)
    .DisposeWith(disposableRegistration);

然后您需要填充 CourseViewModels 集合。

应该从 Courses 中删除 UniversityViewModel 属性。 ReactiveUserControl 没有要解析的 Course

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。