2013-03-11 6 views
6

Мои навыки winforms немного ржавые. Я использую BindingSource для DataGridView. На KeyDownDataGridView Я хочу выбрать следующую/предыдущую запись, которая работает по желанию.BindingSource MoveFirst/MoveLast не работает

Я хочу выбрать первое, если пользователь нажмет 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() называются правильно, но ничего не происходит.

Edit: Интересно, это работает, как ожидалось, когда я вызвать это с помощью кнопки (предыдущий/следующий) вместо DataGridView «s OnKeyDown, какие идеи?

+0

вы могли бы попробовать bs.EndEdit(), после moveFirst/Last? – NDJ

+0

@NDJ: Спасибо, но не работает. –

+0

может быть что-то в сетке переопределяет позицию bs. попробуйте использовать «более позднее» событие, например «KeyUp» –

ответ

2

Сетка автоматически перемещает нижнее положение привязывающего источника при перемещении вверх и вниз.

Если вы хотите, чтобы выбор проходил сверху вниз, и наоборот - вы могли обработать событие grid_KeyDown и проверить его положение. к сожалению, если вы попытаетесь переместить позицию, она будет переопределена событием gridview's Row_Enter. таким образом изменяя позицию источника привязки.

В событии Grid_Keyup позиция уже установлена, поэтому вы не знаете, может ли пользователь просто перейти к строке, или если он хочет отойти от строки. Но установка bindingSource.Position здесь фактически работает - и не становится переопределенной сеткой.

Вы также можете использовать DataGridViewRow.Selected = true, но он не перемещает положение базового связующего источника. Кроме того, он не идеален для сеток, в которых включен мультиселектор.

Уродливая истина заключается в том, что у вас должно быть использовать логическое значение (точно так же, как вы делаете в своем собственном ответе), чтобы контролировать, должна ли строка прыгать или нет.:(

однако вам не нужно контролировать его от PositionChanged случае, вы можете сделать это просто handeling на 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; 
     } 
    } 

Это было настолько чистым, насколько я мог бы получить его

+0

Спасибо за помощь. Слишком плохо, что без этой уродливой переменной нет никакого подхода :) –

2

Благодаря Jens Kloster, я нашел это обходное решение. По его словам, DataGridView уже поддерживает перемещение позиции BindingSource. Поэтому, если у него есть фокус, и вы нажимаете стрелку вверх/вниз, BindingSource's MoveNext/MovePrevious называются неявно.

Я заметил, что выбранный элемент «подпрыгнул» на две позиции, когда я обработал событие KeyUp (а затем событие KeyDown), один для программного и один для встроенного перемещения.

Так что мне нужно только найти способ перемещения позиции от первого до последнего и наоборот, если были нажаты клавиши вверх/вниз. Поэтому я обработал BindingSource.PositionChanged событие, чтобы установить переменную Ий, которые я могу проверить позже:

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

Я по-прежнему открыт для лучшего решения, так как это немного неуклюжее и подвержены ошибкам.

Смежные вопросы