测试当前条目是CollectionViewSource

时间:2019-04-03 09:15:13

标签: c# 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;
    }

一切正常,直到我开始在GUI ComboBox和Text控件中包括“ SelectionChanged”和“ TextChanged”事件。 当我移至集合中的下一个或上一个条目时,将触发这些事件。 一切正常,直到我到达集合中的第一个或最后一个条目。

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

在缺少诸如“ IsCurrentFirst”和“ IsCurrentLast”之类的代码的情况下,谁能提出一种有效的方法来对集合中的条目进行计数,这样我就可以避免越过第一个和最后一个条目?

1 个答案:

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