Search code examples
c#winformsdata-bindingbindingsource

BindingSource MoveFirst/MoveLast doesn't work


My winforms skills are a bit rusty. I'm using a BindingSource for a DataGridView. On KeyDown of the DataGridView i want to select the next/previous record which works as desired.

I want to select the first if the user hits Keys.Down when the last item is selected and select the last if he hits Keys.Up when the first item is selected. But nothing happens then.

Here's the code:

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

Note that bs.MoveFirst()/bs.MoveLast() are called correctly but nothing happens.

Edit: Interesting, it works as expected when i trigger this from a button(previous/next) instead of the DataGridView's OnKeyDown, any ideas?


Solution

  • The grid automatically moves the underderlying bindingsource's position, when you move up and down.

    If you want the selection to go from top to button and vice versa - you could handle the grid_KeyDown event an check it's position. unfortunately if you try moving the posistion, it get overridden by the gridview's Row_Enter Event. thus changing the bindingsource position.

    In the Grid_Keyup event the position is already set, so you dont know if the user just move to the row, or if he/she want to move away from the row. But setting the bindingSource.Position in here actually work - and does not get overridden by the grid.

    You could also use the DataGridViewRow.Selected = true but his does not move the underlying bindingsource's position. Also it is not ideal for grids the multiselect is enabled.

    The ugly truth is that you must use a boolean (just like you do in you own answer), to control if the row should jump or not. :(

    however you dont need to control it from the PositionChanged event, you can do it by just handeling the grid_Keydown event:

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

    This was the as clean as I could get it.