Я хочу реализовать перетаскивание нескольких списков, привязанных к данным, с использованием шаблона MVVM. Я не пытаюсь перетащить между списками, но хочу, чтобы пользователь мог перетащить/удалить listboxitems в каждом списке, чтобы они могли изменить порядок сортировки. Я нашел этот пост на SO, который был ОЧЕНЬ полезен:
WPF С#: переупорядочить элементы в списке с помощью перетаскивания
Я хотел попробовать и сделать методы более "родовыми", чтобы он работал на любом списке, который привязан к различным типам наблюдаемых коллекций. Так скажите, что это мой XAML в VIEW:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type ListBoxItem}" x:Key="ListBoxItemDragDrop">
<Setter Property="AllowDrop" Value="True" />
<EventSetter Event="PreviewMouseMove" Handler="ListBoxItem_PreviewMouseMoveEvent" />
<EventSetter Event="Drop" Handler="listbox1_Drop" />
</Style>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox Name="listbox1"
ItemsSource="{Binding OCofType1}"
ItemContainerStyle="{StaticResource ListBoxItemDragDrop}" />
<ListBox Name="listbox2" Grid.Column="1"
ItemsSource="{Binding OCofType2}"
ItemContainerStyle="{StaticResource ListBoxItemDragDrop}"/>
</Grid>
</Window>
Где привязки OC представляют собой ObservalbeCollection <Type1 > и ObservalbeCollection <Type2 > . Вот метод в VIEW, который захватывает событие перемещения мыши и проверяет, является ли это перетаскиванием:
void ListBoxItem_PreviewMouseMoveEvent(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && sender is ListBoxItem)
{
ListBoxItem draggedItem = (ListBoxItem)sender;
DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move);
draggedItem.IsSelected = true;
}
}
Это кажется "общим". Далее был бы метод, также в VIEW, обрабатывает капли, и вот где я застрял:
void ListBoxItem_Drop(object sender, DragEventArgs e)
{
object Target = ((ListBoxItem)(sender)).DataContext;
object Dropped = e.Data.GetData(Target.GetType());
int RemoveIndex = listbox1.Items.IndexOf(Dropped);
int TargetIndex = listbox1.Items.IndexOf(Target);
ListBox container = ((DependencyObject)sender).GetAncestor<ListBox>();
if (RemoveIndex < TargetIndex)
{
//THESE WILL NOT WORK IF I AM DOING BINDINGS THROUGH THE ITEMSSOURCE
//container.Items.Insert(RemoveIndex + 1, Dropped);
//container.Items.RemoveAt(RemoveIndex);
//SO HAVE TO USE THE ITEMSSOURCE DIRECTLY BUT HOW WITHOUT A SPECIFIC CAST TO THE OC<TYPE#>
container.ItemsSource.Insert(RemoveIndex + 1, Dropped); //ERROR: IENUMERATOR DOES NOT CONTAIN A DEFINITION FOR INSERT....
container.ItemsSource.RemoveAt(RemoveIndex); //ERROR: IENUMERATOR DOES NOT CONTAIN A DEFINITION FOR REMOVEAT....
}
else
if (container.Items.Count > RemoveIndex)
{
//THESE WILL NOT WORK IF I AM DOING BINDINGS THROUGH THE ITEMSSOURCE
//container.Items.Insert(TargetIndex, Dropped);
//container.Items.RemoveAt(RemoveIndex + 1);
//SO HAVE TO USE THE ITEMSSOURCE DIRECTLY BUT HOW WITHOUT A SPECIFIC CAST TO THE OC<TYPE#>
container.ItemsSource.Insert(TargetIndex, Dropped); //ERROR: IENUMERATOR DOES NOT CONTAIN A DEFINITION FOR INSERT....
container.ItemsSource.RemoveAt(RemoveIndex + 1); //ERROR: IENUMERATOR DOES NOT CONTAIN A DEFINITION FOR REMOVEAT....
}
}
То, что найти функции предков, это (из другого сообщения в SO):
static T FindAnchestor<T>(DependencyObject current) where T : DependencyObject
{
do
{
if (current is T)
return (T)current;
current = VisualTreeHelper.GetParent(current);
}
while (current != null);
return null;
}
В функции drop это может работать, если я непосредственно добавляю в списки ListBox List. Но так как я делаю привязки к коллекциям в VIEWMODEL, это будет ошибкой, говоря, что я должен работать с этими объектами, хотя с ItemsSource. Но если я использую ItemSource, мне придется создавать изменчивые версии этой функции для каждого типа OC, так как я бы не стал отличать ItemsSource во время выполнения. Я мог бы сохранить его до 1 функции, используя оператор if, который определяет, что его явно использовать, но было бы намного чище не забывать обновлять это, если для каждого нового OC оно применяется.
Вопрос в том, как я могу добавить/переместить элементы в ItemsSource, не зная точно, что тоже делать?
Спасибо за любую помощь.