C# 测试当前条目是否是CollectionViewSource中的第一个或最后一个条目

C# 测试当前条目是否是CollectionViewSource中的第一个或最后一个条目,c#,wpf,collectionviewsource,C#,Wpf,Collectionviewsource,我正在通过实体框架将MS SQL Server表中的行读取到C#CollectionViewSource中。一行=一个集合条目 我使用数据绑定将每个CollectionViewSource条目的数据元素连接到WPF GUI的控件。 用户使用GUI上的按钮,使用下面的命令处理程序向后和向前翻页集合条目 private void DisplayNextRecordButtonCommandHandler(object sender, ExecutedRoutedEventArgs e)

我正在通过实体框架将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组合框和文本控件中包含“SelectionChanged”和“TextChanged”事件之前,所有这些都工作得很好。 当我移动到集合中的下一个或上一个条目时,将触发这些事件。 在我找到集合中的第一个或最后一个条目之前,一切都正常

“IsCurrentAfterLast”测试并没有阻止我跳过集合中的最后一个条目,当我这样做时,我会得到一个“对象引用未设置为对象实例”异常。 我假设异常是由“SelectionChanged”和“TextChanged”事件在第一个集合条目之前或最后一个集合条目之后遇到虚假数据引起的

在没有像“IsCurrentFirst”和“IsCurrentLast”这样圆滑的东西的情况下,有谁能建议一种有效的方法来计算集合中的条目,这样我就可以避免越过第一个和最后一个

如果没有像“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

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();
    }
}

您可以钩住
CurrentChanging
-事件,并将
CurrentChangingEventArgs设置为
true
,如果您在集合的末尾,并且要移动过去?
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();
    }
}