Что вызывает событие ListChangedType.ItemMoved ListChange в BindingList <T>?

У меня есть BindingList (T), который я показываю в DataGrid. Я наблюдаю за событиями ListChanged и выполняю различные действия при возникновении события ListChanged.

Я проверяю аргумент ListChangeType, чтобы проверить, как был изменен список, и затем соответствующим образом реагировать. Однако я заметил, что существует тип события ListChanged ItemMoved.

У меня есть кнопки для "Move Up" и "Move Down" для перемещения элементов вверх и вниз по списку. Но они фактически удаляют выбранный элемент, а затем снова вставляют его в более высокое или нижнее положение.

Однако я не вижу никакого метода BindingList (T), который выглядит так, будто он перемещает элемент в списке. Так что я что-то упустил или нет способа переместить элемент в BindingList, который также вызовет событие ListChanged типа ItemMoved?

void FloorCollection_ListChanged(object sender, ListChangedEventArgs e)
{
    if (e.ListChangedType == ListChangedType.ItemAdded)
    {    
        //DO STUFF
    }
    else if (e.ListChangedType == ListChangedType.ItemDeleted)
    {
        //DO STUFF
    }
    else if (e.ListChangedType == ListChangedType.ItemMoved)
    {
        //HOW DO I GET THIS CODE TO RUN?
    }
    else if (e.ListChangedType == ListChangedType.ItemChanged)
    {
        //DO STUFF
    }
}

Ответ 1

К сожалению, ничто в BindingList не вызовет событие ListChanged с ListChangedType, установленным в ListChangedType.ItemMoved. BindingList наследует от Collection, который не предоставляет никакой поддержки для "перемещения" элементов в списке. BindingList не добавляет никакой поддержки этому типу поведения.

Если вам действительно нужно/нужно отвечать на события ListChangedType.ItemMoved, лучшим вариантом является извлечение собственного класса из BindingList и предоставление собственных методов Move. Внутри этих методов вам необходимо временно приостановить сбор событий ListChanged, выполнить перемещение, удалив/добавив, поднимите событие ListChanged самостоятельно с помощью соответствующего ItemMoved ListChangedType, а затем верните приостановление создания событий ListChanged.

Это выглядело бы так: */

public class CustomBindingList<T> : BindingList<T>
{
   public void Move(T item, int index)
   {
      bool raiseListChangedEvents = this.RaiseListChangedEvents;
      try
      {
         this.RaiseListChangedEvents = false;
         int oldIndex = this.IndexOf(item);
         this.Remove(item);
         this.InsertItem(index, item);    
         this.OnListChanged(new ListChangedEventArgs(ListChangedType.ItemMoved, index, oldIndex));
      }
      finally
      {
         this.RaiseListChangedEvents = raiseListChangedEvents;
      }
   }
}

* Полностью непроверенный код, но он должен проиллюстрировать основные моменты.

Ответ 2

Он запускает, если для источника привязки применяется сортировка, если вы изменили и данные, которые хранятся в поле сортировки, а затем измените положение записи, а затем триггеры события.

Ответ 3

В отличие от ответов Скотта, вы можете сделать что-то вроде этого метода расширения:

//Dumping ground for miscellaneous functions
public static class Misc
{
   //Swap items at index positions 'index0' and 'index1' in the list
   public static void Swap<T>(this BindingList<T> list, int index0, int index1, bool reset_bindings)
   {
      if (index0 == index1) return;
      bool raise_events = list.RaiseListChangedEvents;
      try
      {
         list.RaiseListChangedEvents = false;
         T tmp = list[index0];
         list[index0] = list[index1];
         list[index1] = tmp;
         list.RaiseListChangedEvents = raise_events;
         if (reset_bindings) list.ResetBindings();
      }
      finally
      {
         list.RaiseListChangedEvents = raise_events;
      }
   }
}

Это не приводит к событиям ItemMoved, которые вы выполняли, но сохраняет необходимость подкласса BindingList < > . Вы можете поднять событие Reset (используя ResetBindings()) после того, как закончите перемещение элементов в списке. Может быть полезно...