测试当前条目是 CollectionViewSource 中的第一个还是最后一个条目

Joe*_*Joe 2 c# wpf collectionviewsource

我正在通过实体框架将 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;
    }
Run Code Online (Sandbox Code Playgroud)

在我开始在 GUI ComboBox 和 Text 控件中包含“SelectionChanged”和“TextChanged”事件之前,一切都运行良好。当我移动到集合中的下一个或上一个条目时会触发这些事件。一切正常,直到我到达集合中的第一个或最后一个条目。

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

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

Nko*_*osi 6

如果没有像“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;
    }
}
Run Code Online (Sandbox Code Playgroud)

扩展方法现在应该允许这样的检查。

创建一些ICommand可以直接连接到上一个和下一个按钮的派生实现。

移动当前到下一个命令

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

移动当前到上一个命令

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

这简化了与视图模型中的命令的绑定

public ICommand Next => new MoveCurrentToNextCommand(MyCollectionViewSource.View);
public ICommand Previous => new MoveCurrentToPreviousCommand(MyCollectionViewSource.View);
Run Code Online (Sandbox Code Playgroud)

这里有一些关于命令的单元测试,以进行良好的衡量。

[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();
    }
}
Run Code Online (Sandbox Code Playgroud)