C# WPF 中的 ReactiveUI:列表的绑定列表
ReactiveUI in C# WPF: Bind List of List
我刚开始使用 C# - WPF 中的 ReactiveUI 和 MVVM。
我创建了一个测试项目,其目标是表示一个对象链表。
每个大学列表都有一个课程列表。在课程中,考试由学生匿名提交。
我首先只显示大学列表。这行得通。
但是我无法显示课程列表。我看到一个列表框,但条目是空的。 (为了清楚起见,我暂时省略了考试的介绍。)
- 大学0
- 课程 0
- 考试 0:待定
- 考试 1:完成
- 课程 1
- 考试 2:进行中
- 考试 3:完成
- 大学1
- 课程 3
- 考试 4:完成
- 考试 5:完成
我假设在 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,
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;
}
}
UniversityView
应该绑定到 CourseViewModels
而不是 Courses
才能解析 CourseView
:
this.OneWayBind(ViewModel,
viewModel => viewModel.CourseViewModels,
view => view.ListBoxCourses.ItemsSource)
.DisposeWith(disposableRegistration);
然后您需要填充 CourseViewModels
集合。
Courses
属性 应该从 UniversityViewModel
中删除。 Course
.
没有要解决的 ReactiveUserControl
我刚开始使用 C# - WPF 中的 ReactiveUI 和 MVVM。
我创建了一个测试项目,其目标是表示一个对象链表。 每个大学列表都有一个课程列表。在课程中,考试由学生匿名提交。 我首先只显示大学列表。这行得通。
但是我无法显示课程列表。我看到一个列表框,但条目是空的。 (为了清楚起见,我暂时省略了考试的介绍。)
- 大学0
- 课程 0
- 考试 0:待定
- 考试 1:完成
- 课程 1
- 考试 2:进行中
- 考试 3:完成
- 课程 0
- 大学1
- 课程 3
- 考试 4:完成
- 考试 5:完成
- 课程 3
我假设在 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,
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;
}
}
UniversityView
应该绑定到 CourseViewModels
而不是 Courses
才能解析 CourseView
:
this.OneWayBind(ViewModel,
viewModel => viewModel.CourseViewModels,
view => view.ListBoxCourses.ItemsSource)
.DisposeWith(disposableRegistration);
然后您需要填充 CourseViewModels
集合。
Courses
属性 应该从 UniversityViewModel
中删除。 Course
.
ReactiveUserControl