BindingSource MoveFirst/MoveLast doesn't work

本文关键字:work doesn MoveFirst MoveLast BindingSource | 更新日期: 2023-09-27 18:03:23

我的winforms技能有点生疏了。我用BindingSource代替DataGridView。在DataGridViewKeyDown上,我想选择按需要工作的下一个/上一个记录。

如果用户在选择最后一项时点击Keys.Down,则选择第一个;如果用户在选择第一项时点击Keys.Up,则选择最后一个。但是什么也没发生。

代码如下:

private void  Grid_Keydown(Object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Up)
        previousItem();
    else if (e.KeyCode == Keys.Down)
        nextItem();
}
private void previousItem()
{
    BindingSource bs = null;
    switch (this.Type) // a custom enum
    {
        case AdminType.Channel:  
            bs = channelBindingSource;
            break;
        default:
            break;
    }
    if (bs.Position - 1 < 0)
        bs.MoveLast();
    else
        bs.MovePrevious();
}
private void nextItem()
{
    BindingSource bs = null;
    switch (this.Type)
    {
        case AdminType.Channel:
            bs = channelBindingSource;
            break;
        default:
            break;
    }
    if (bs.Position + 1 >= bs.Count)
        bs.MoveFirst();
    else
        bs.MoveNext();
}

注意bs.MoveFirst()/bs.MoveLast()被正确调用,但是什么都没有发生。

编辑:有趣的是,当我从按钮(上/下)而不是DataGridViewOnKeyDown触发此时,它按预期工作,有什么想法吗?

BindingSource MoveFirst/MoveLast doesn't work

当你上下移动时,网格会自动移动底层绑定源的位置。

如果你想选择从顶部到按钮,反之亦然-你可以处理grid_KeyDown事件并检查它的位置。不幸的是,如果你尝试移动位置,它会被gridview的Row_Enter事件覆盖。从而改变了绑定源的位置。

Grid_Keyup事件中,位置已经设置好了,所以你不知道用户是刚刚移动到该行,还是他/她想从该行移开。但是在这里设置bindingSource.Position实际上是有效的-并且不会被网格覆盖。

您也可以使用DataGridViewRow.Selected = true,但它不会移动底层绑定源的位置。此外,它不是理想的网格,多选是启用的。

一个丑陋的事实是,必须使用布尔值(就像您在自己的答案中所做的那样)来控制行是否应该跳转。(

但是你不需要从PositionChanged事件中控制它,你可以通过处理grid_Keydown事件来做到这一点:

 private bool _changePost;
    private void dataGridView1_KeyUp(object sender, KeyEventArgs e)
    {
        var view = sender as DataGridView;
        var bs = bindingSource1;
        if (e.KeyData == Keys.Up)
        {
            if (bs.Position == 0 && _changePost)
            {
                _changePost = false;
                bs.MoveLast();
            }
            if (bs.Position == 0 && !_changePost)
                _changePost = true;
        }
        else if (e.KeyData == Keys.Down)
        {
            if (bs.Position == bs.Count - 1 && _changePost)
            {
                bs.MoveFirst();
                _changePost = false;
            }
            if (bs.Position == bs.Count - 1 && !_changePost)
                _changePost = true;
        }
    }

这是我能弄到的最干净的了

多亏了Jens Kloster,我找到了这个解决方案。正如他提到的DataGridView已经支持移动它的BindingSource的位置。所以如果它有焦点,你点击向上/向下箭头,BindingSourceMoveNext/MovePrevious被隐式调用。

我注意到,当我处理KeyUp事件(后来是KeyDown事件)时,所选项目"跳"了两个位置,一个用于编程,一个用于内置移动。

所以我只需要找到一种方法来移动位置从第一个到最后一个,反之亦然,如果向上/向下键被按下。因此,我已经处理了BindingSource.PositionChanged事件来设置一个bool变量,我可以稍后检查:

bool positionChanged = false;
private void Source_PositionChanged(object sender, EventArgs e)
{
    positionChanged = true;
}
private void Grid_KeyUp(Object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Up)
        previousItem();
    else if (e.KeyCode == Keys.Down)
        nextItem();
    positionChanged = false;
}
private void previousItem()
{
    BindingSource bs = null;
    switch (this.Type)
    {
        case AdminType.Channel:
            bs = channelBindingSource;
            break;
        default:
            break;
    }
    if (!positionChanged && bs.Position == 0)
        bs.MoveLast();
    else if (!positionChanged)
        bs.MovePrevious();
}
private void nextItem()
{
    BindingSource bs = null;
    switch (this.Type)
    {
        case AdminType.Channel:
            bs = channelBindingSource;
            break;
        default:
            break;
    }
    if (!positionChanged && bs.Position == bs.Count - 1)
        bs.MoveFirst();
    else if (!positionChanged)
        bs.MoveNext();
}

我仍然对更好的解决方案持开放态度,因为这有点笨拙和容易出错。