测试当前条目是 CollectionViewSource 中的第一个还是最后一个条目
Test if the current entry is the first or last entry in a CollectionViewSource
我正在通过 Entity Framework 从 MS SQL 服务器 table 读取行到 C# CollectionViewSource 中。一行 = 一个集合条目。
我使用数据绑定将每个 CollectionViewSource 条目的数据元素连接到 WPF GUI 的控件。
用户使用 GUI 上的按钮使用如下命令处理程序在集合条目中向后和向前翻页。
private void DisplayNextRecordButtonCommandHandler(object sender, ExecutedRoutedEventArgs e) // Select the Next record for Display.
{
MyCollectionViewSource.View.MoveCurrentToNext();
//Prevent the display of an "empty" record
if (MyCollectionViewSource.View.IsCurrentAfterLast)
{
orgUnitAssetRskViewSource.View.MoveCurrentToPrevious();
}
selectedRecordPosition = orgUnitAssetRskViewSource.View.CurrentPosition;
}
在我开始在我的 GUI ComboBox 和 Text 控件中包含 "SelectionChanged" 和 "TextChanged" 事件之前,一切都运行良好。
当我移动到集合中的下一个或上一个条目时,这些事件会触发。
一切正常,直到我到达集合中的第一个或最后一个条目。
"IsCurrentAfterLast" 测试并没有阻止我翻阅集合中的最后一个条目,当我这样做时,我得到一个 "Object reference not set to an instance of an object" 异常。
我假设异常是在 "SelectionChanged" 和 "TextChanged" 事件在第一个或最后一个集合条目之前遇到虚假数据时引起的。
在没有像 "IsCurrentFirst" 和 "IsCurrentLast" 这样巧妙的东西的情况下,任何人都可以建议一种有效的方法来计算集合中的条目,这样我就可以避免超过第一个和最后一个吗?
In the absence of something slick like "IsCurrentFirst" and "IsCurrentLast"
足够简单,可以在 ICollectionView
抽象上创建一些扩展方法来提供所需的功能
public static class CollectionViewExtensions {
public static bool IsCurrentFirst(this ICollectionView view) {
return view.CurrentItem != null && view.CurrentPosition == 0;
}
public static bool IsCurrentLast(this ICollectionView view) {
if (view.CurrentItem == null) return false;
var index = view.CurrentPosition;
var max = view.Count() - 1;
return index == max;
}
public static bool CanMoveCurrentToNext(this ICollectionView view) {
return !view.IsCurrentLast();
}
public static bool CanMoveCurrentToPrevious(this ICollectionView view) {
return !view.IsCurrentFirst();
}
static int Count(this ICollectionView source) {
int count = 0;
var e = source.GetEnumerator();
checked {
while (e.MoveNext()) count++;
}
return count;
}
}
扩展方法现在应该允许进行此类检查。
创建一些可以直接挂接到上一个和下一个按钮的派生 ICommand
实现。
MoveCurrentToNextCommand
public class MoveCurrentToNextCommand : ICommand {
private readonly ICollectionView view;
public MoveCurrentToNextCommand(ICollectionView view) {
this.view = view;
this.view.CurrentChanged += (s, e) => {
CanExecuteChanged(this, EventArgs.Empty);
};
}
public event EventHandler CanExecuteChanged = delegate { };
public bool CanExecute(object parameter = null) => view.CanMoveCurrentToNext();
public void Execute(object parameter = null) {
if (CanExecute(parameter))
view.MoveCurrentToNext();
}
}
MoveCurrentToPreviousCommand
public class MoveCurrentToPreviousCommand : ICommand {
private readonly ICollectionView view;
public MoveCurrentToPreviousCommand(ICollectionView view) {
this.view = view;
this.view.CurrentChanged += (s, e) => {
CanExecuteChanged(this, EventArgs.Empty);
};
}
public event EventHandler CanExecuteChanged = delegate { };
public bool CanExecute(object parameter = null) => view.CanMoveCurrentToPrevious();
public void Execute(object parameter = null) {
if (CanExecute(parameter))
view.MoveCurrentToPrevious();
}
}
这简化了与视图模型中命令的绑定
public ICommand Next => new MoveCurrentToNextCommand(MyCollectionViewSource.View);
public ICommand Previous => new MoveCurrentToPreviousCommand(MyCollectionViewSource.View);
以下是对命令进行的一些单元测试,以备不时之需。
[TestClass]
public class CollectionViewCommandsTests {
[TestMethod]
public void Should_Not_Move_Previous() {
//Arrange
var items = new[] { new object(), new object(), new object() };
var view = new CollectionView(items);
var expected = view.CurrentItem;
bool changed = false;
ICommand command = new MoveCurrentToPreviousCommand(view);
command.CanExecuteChanged += delegate {
changed = true;
};
//Act
command.Execute(null);
//Assert
var actual = view.CurrentItem;
actual.Should().Be(expected);
changed.Should().BeFalse();
}
[TestMethod]
public void Should_Move_Next() {
//Arrange
var items = new[] { new object(), new object(), new object() };
var view = new CollectionView(items);
var expected = items[1];
bool changed = false;
ICommand command = new MoveCurrentToNextCommand(view);
command.CanExecuteChanged += delegate {
changed = true;
};
//Act
command.Execute(null);
//Assert
var actual = view.CurrentItem;
actual.Should().Be(expected);
changed.Should().BeTrue();
}
[TestMethod]
public void Should_Not_Move_Next() {
//Arrange
var items = new[] { new object(), new object(), new object() };
var view = new CollectionView(items);
view.MoveCurrentToLast();
var expected = view.CurrentItem;
bool changed = false;
ICommand command = new MoveCurrentToNextCommand(view);
command.CanExecuteChanged += delegate {
changed = true;
};
//Act
command.Execute(null);
//Assert
var actual = view.CurrentItem;
actual.Should().Be(expected);
changed.Should().BeFalse();
}
[TestMethod]
public void Should_Move_Previous() {
//Arrange
var items = new[] { new object(), new object(), new object() };
var view = new CollectionView(items);
view.MoveCurrentToLast();
var expected = items[1];
bool changed = false;
ICommand command = new MoveCurrentToPreviousCommand(view);
command.CanExecuteChanged += delegate {
changed = true;
};
//Act
command.Execute(null);
//Assert
var actual = view.CurrentItem;
actual.Should().Be(expected);
changed.Should().BeTrue();
}
}
我正在通过 Entity Framework 从 MS SQL 服务器 table 读取行到 C# CollectionViewSource 中。一行 = 一个集合条目。
我使用数据绑定将每个 CollectionViewSource 条目的数据元素连接到 WPF GUI 的控件。 用户使用 GUI 上的按钮使用如下命令处理程序在集合条目中向后和向前翻页。
private void DisplayNextRecordButtonCommandHandler(object sender, ExecutedRoutedEventArgs e) // Select the Next record for Display.
{
MyCollectionViewSource.View.MoveCurrentToNext();
//Prevent the display of an "empty" record
if (MyCollectionViewSource.View.IsCurrentAfterLast)
{
orgUnitAssetRskViewSource.View.MoveCurrentToPrevious();
}
selectedRecordPosition = orgUnitAssetRskViewSource.View.CurrentPosition;
}
在我开始在我的 GUI ComboBox 和 Text 控件中包含 "SelectionChanged" 和 "TextChanged" 事件之前,一切都运行良好。 当我移动到集合中的下一个或上一个条目时,这些事件会触发。 一切正常,直到我到达集合中的第一个或最后一个条目。
"IsCurrentAfterLast" 测试并没有阻止我翻阅集合中的最后一个条目,当我这样做时,我得到一个 "Object reference not set to an instance of an object" 异常。 我假设异常是在 "SelectionChanged" 和 "TextChanged" 事件在第一个或最后一个集合条目之前遇到虚假数据时引起的。
在没有像 "IsCurrentFirst" 和 "IsCurrentLast" 这样巧妙的东西的情况下,任何人都可以建议一种有效的方法来计算集合中的条目,这样我就可以避免超过第一个和最后一个吗?
In the absence of something slick like "IsCurrentFirst" and "IsCurrentLast"
足够简单,可以在 ICollectionView
抽象上创建一些扩展方法来提供所需的功能
public static class CollectionViewExtensions {
public static bool IsCurrentFirst(this ICollectionView view) {
return view.CurrentItem != null && view.CurrentPosition == 0;
}
public static bool IsCurrentLast(this ICollectionView view) {
if (view.CurrentItem == null) return false;
var index = view.CurrentPosition;
var max = view.Count() - 1;
return index == max;
}
public static bool CanMoveCurrentToNext(this ICollectionView view) {
return !view.IsCurrentLast();
}
public static bool CanMoveCurrentToPrevious(this ICollectionView view) {
return !view.IsCurrentFirst();
}
static int Count(this ICollectionView source) {
int count = 0;
var e = source.GetEnumerator();
checked {
while (e.MoveNext()) count++;
}
return count;
}
}
扩展方法现在应该允许进行此类检查。
创建一些可以直接挂接到上一个和下一个按钮的派生 ICommand
实现。
MoveCurrentToNextCommand
public class MoveCurrentToNextCommand : ICommand {
private readonly ICollectionView view;
public MoveCurrentToNextCommand(ICollectionView view) {
this.view = view;
this.view.CurrentChanged += (s, e) => {
CanExecuteChanged(this, EventArgs.Empty);
};
}
public event EventHandler CanExecuteChanged = delegate { };
public bool CanExecute(object parameter = null) => view.CanMoveCurrentToNext();
public void Execute(object parameter = null) {
if (CanExecute(parameter))
view.MoveCurrentToNext();
}
}
MoveCurrentToPreviousCommand
public class MoveCurrentToPreviousCommand : ICommand {
private readonly ICollectionView view;
public MoveCurrentToPreviousCommand(ICollectionView view) {
this.view = view;
this.view.CurrentChanged += (s, e) => {
CanExecuteChanged(this, EventArgs.Empty);
};
}
public event EventHandler CanExecuteChanged = delegate { };
public bool CanExecute(object parameter = null) => view.CanMoveCurrentToPrevious();
public void Execute(object parameter = null) {
if (CanExecute(parameter))
view.MoveCurrentToPrevious();
}
}
这简化了与视图模型中命令的绑定
public ICommand Next => new MoveCurrentToNextCommand(MyCollectionViewSource.View);
public ICommand Previous => new MoveCurrentToPreviousCommand(MyCollectionViewSource.View);
以下是对命令进行的一些单元测试,以备不时之需。
[TestClass]
public class CollectionViewCommandsTests {
[TestMethod]
public void Should_Not_Move_Previous() {
//Arrange
var items = new[] { new object(), new object(), new object() };
var view = new CollectionView(items);
var expected = view.CurrentItem;
bool changed = false;
ICommand command = new MoveCurrentToPreviousCommand(view);
command.CanExecuteChanged += delegate {
changed = true;
};
//Act
command.Execute(null);
//Assert
var actual = view.CurrentItem;
actual.Should().Be(expected);
changed.Should().BeFalse();
}
[TestMethod]
public void Should_Move_Next() {
//Arrange
var items = new[] { new object(), new object(), new object() };
var view = new CollectionView(items);
var expected = items[1];
bool changed = false;
ICommand command = new MoveCurrentToNextCommand(view);
command.CanExecuteChanged += delegate {
changed = true;
};
//Act
command.Execute(null);
//Assert
var actual = view.CurrentItem;
actual.Should().Be(expected);
changed.Should().BeTrue();
}
[TestMethod]
public void Should_Not_Move_Next() {
//Arrange
var items = new[] { new object(), new object(), new object() };
var view = new CollectionView(items);
view.MoveCurrentToLast();
var expected = view.CurrentItem;
bool changed = false;
ICommand command = new MoveCurrentToNextCommand(view);
command.CanExecuteChanged += delegate {
changed = true;
};
//Act
command.Execute(null);
//Assert
var actual = view.CurrentItem;
actual.Should().Be(expected);
changed.Should().BeFalse();
}
[TestMethod]
public void Should_Move_Previous() {
//Arrange
var items = new[] { new object(), new object(), new object() };
var view = new CollectionView(items);
view.MoveCurrentToLast();
var expected = items[1];
bool changed = false;
ICommand command = new MoveCurrentToPreviousCommand(view);
command.CanExecuteChanged += delegate {
changed = true;
};
//Act
command.Execute(null);
//Assert
var actual = view.CurrentItem;
actual.Should().Be(expected);
changed.Should().BeTrue();
}
}