简体   繁体   English

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

[英]ReactiveUI in C# WPF: Bind List of List

I am just starting with ReactiveUI and MVVM in C# - WPF.我刚从 C# - WPF 中的 ReactiveUI 和 MVVM 开始。

I have created a test project whose goal is to represent a chained list of objects.我创建了一个测试项目,其目标是表示对象的链表。 A list of universities each has a list of courses.每所大学都有一个课程列表。 In the courses, exams are submitted anonymously by students.在课程中,考试由学生匿名提交。 I started by displaying only the list of universities.我首先只显示大学列表。 This works.这行得通。

But I can't manage to display the list of courses.但我无法显示课程列表。 I see a ListBox, but the entries are empty.我看到一个 ListBox,但条目是空的。 (For the time being, I have omitted the presentation of the exams for the sake of clarity.) (暂时,为了清楚起见,我省略了考试的介绍。)

  1. University0大学0
    • Course0课程0
      • Exam0: pending考试0:待定
      • Exam1: finished考试1:完成
    • Course1课程1
      • Exam2: ongoing考试2:正在进行
      • Exam3: finished考试3:完成
  2. University1大学1
    • Course3课程3
      • Exam4: finished考试4:完成
      • Exam5: finished考试5:完成

I assume that in the UniversityViewModel.cs I have to bind the list of courses somehow, but how?我假设在 UniversityViewModel.cs 中我必须以某种方式绑定课程列表,但是如何?

For starters, I used the example on the ReactiveUI page as a guide: A Compelling Example对于初学者,我使用 ReactiveUI 页面上的示例作为指南: 一个引人注目的示例

AppViewModel.cs 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大学.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 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 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 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课程.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 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 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,
                    viewModel => viewModel.Name,
                    view => view.nameRun.Text)
                    .DisposeWith(disposableRegistration);
            });
        }
    }
}

CourseViewModel.cs CourseViewModel.cs

using ReactiveUI;

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

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

        public string Name => _course.Name;
    }
}

The UniversityView should bind to CourseViewModels instead of Courses for the CourseView to be resolved: UniversityView应该绑定到CourseViewModels而不是Courses才能解析CourseView

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

You will then need to populate the CourseViewModels collection.然后,您将需要填充CourseViewModels集合。

The Courses property should be removed from the UniversityViewModel . Courses属性应该从UniversityViewModel中删除。 There is no ReactiveUserControl to be resolved for Course . Course没有要解决的ReactiveUserControl

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM