[英]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.) (暂时,为了清楚起见,我省略了考试的介绍。)
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.