我正在通过实体框架将MS SQL Server表中的行读取到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”测试不会阻止我调页经过集合中的最后一个条目,当我这样做时,我会收到“对象引用未设置为对象实例”的异常。 我假设该异常是在“ SelectionChanged”和“ TextChanged”事件在第一个或最后一个集合条目之前遇到虚假数据时引起的。
在缺少诸如“ IsCurrentFirst”和“ IsCurrentLast”之类的代码的情况下,谁能提出一种有效的方法来对集合中的条目进行计数,这样我就可以避免越过第一个和最后一个条目?
答案 0 :(得分:1)
在没有诸如“ IsCurrentFirst”和“ 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();
}
}