BindingSource MoveFirst / MoveLast not working

My winforms skills are a little rusty. I am using BindingSource for a DataGridView . In KeyDown DataGridView I want to select the next / previous record, which works as desired.

I want to select the first if the user presses Keys.Down when the last item is selected, and select the last if it gets into Keys.Up when the first item is selected. But then nothing happens.

Here is 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() called correctly, but nothing happens.

Change Interestingly, it works as expected when I launch it using the button (previous / next) instead of the DataGridView OnKeyDown , any ideas?

+6
source share
2 answers

The grid automatically moves the position of the lower snap when you move up and down.

If you want the selection to go from the top to the button and vice versa, you could handle the grid_KeyDown event to check its position. unfortunately, if you try to move a position, it will be overridden by the gridview Row_Enter event. thus changing the position of the binding source.

In the Grid_Keyup event Grid_Keyup position is already set, so you do not know if the user will simply move to the row, or if he wants to move away from the row. But setting bindingSource.Position here actually works - and is not overridden by the grid.

You can also use DataGridViewRow.Selected = true , but it does not move the main position of the binding. Also, it is not ideal for grids in which the multi selector is turned on.

The ugly truth is that you should use the boolean (as in your own answer) to control whether the line should jump or not. :(

however, you do not need to control it from the PositionChanged event, you can do this by simply handling 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; } } 

It was as clean as I could get it.

+2
source

Thanks to Jens Kloster, I found this workaround. According to him, the DataGridView already supports moving its BindingSource position. Therefore, if it has focus and you aim up / down, BindingSource MovePrevious / MovePrevious are called implicitly.

I noticed that the selected item “bounced” two positions when I handled the KeyUp event (which later is the KeyDown ), one for the program and one for the built-in move.

Therefore, I only need to find a way to move the position from the first to the last and vice versa if the up / down keys were pressed. So I handled the BindingSource.PositionChanged event to set the bool variable, which I can check later:

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

I am still open to better solutions, as it is a bit uncomfortable and error prone.

+2
source

All Articles