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



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

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

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

  1. 大学0
    • 课程0
      • Exam0:挂起
      • 示例1:已完成
    • 课程1
      • 考试2:正在进行
      • Exam3:已完成
  2. 大学1
    • 课程3
      • 考试4:已完成
      • 考试5:已完成

我认为在UniversityViewModel.cs中,我必须以某种方式绑定课程列表,但如何绑定?

首先,我使用了ReactiveUI页面上的示例作为指南:一个引人注目的示例

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,
viewModel => viewModel.Name,
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;
}
}

对于要解析的CourseViewUniversityView应该绑定到CourseViewModels而不是Courses

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

然后,您需要填充CourseViewModels集合。

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

最新更新