一般拖放ListBoxItems [英] Drag and Drop ListBoxItems generically

查看:80
本文介绍了一般拖放ListBoxItems的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用MVVM模式在绑定了数据的多个列表框中实现拖放.我不是想在列表框之间拖放,而是希望用户能够在每个列表框中拖放列表框项目,以便他们可以重新排列排序顺序.我在SO上找到了这篇帖子,对您有很大帮助:

I want to implement a drag and drop on multiple listboxes that are data bound - using the MVVM pattern. I am not trying to drag and drop between listboxes but rather want the user to be able to drag/drop listboxitems in each listbox so they can rearrange the sort order. I found this post on SO which was VERY helpful:

WPF C#:通过拖动重新排列列表框中的项目放下

我想尝试使方法更通用",以便它可以在绑定到不同类型的Observable Collections的任何列表框中使用.所以说这是我在VIEW中的XAML:

I wanted to try and make the methods more "generic" so that it would work on any listbox that is binding to different types of Observable Collections. So say this is my XAML in the 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中的方法,它捕获鼠标移动事件并检查是否为拖动事件:

Where the OC bindings are ObservalbeCollection<Type1> and ObservalbeCollection<Type2>. Here is the method in the VIEW that grabs the mouse move event and checks if it is a drag:

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中,处理下降,这就是我遇到的问题:

This seems "generic" enough. Next would be the method, also in the VIEW, the handles the drop and this is where I get stuck:

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上的另一篇文章):

That find ancestor functions is this (from another post on 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;
}

在放置函数中,如果我直接添加到ListBox的List集合中,则此方法可能有效.但是由于我正在对VIEWMODEL中的集合进行绑定,所以说我必须通过ItemsSource处理这些对象会出错.但是,如果我使用ItemsSource,则必须为每种OC类型制作该函数的可变版本,因为我也不会在运行时强制转换ItemsSource.我可以使用if语句将其限制为1个函数,该语句确定将其强制转换为什么内容,但这将是很多清理程序,而不必记住要为每个新的OC对其进行更新.

In the drop function, this might work if I was directly adding to the ListBox's List collections. But since I am doing bindings to collections in the VIEWMODEL, it will error saying that I have to work with those objects though the ItemsSource. But if I use the ItemsSource I would have to make mutible versions of the function for each OC Type since I would not what to cast the ItemsSource too at run time. I could keep it down to 1 function using an if statement which determine what to cast it to explicitly but it would be alot cleaner not having to remember to update that if for each new OC it is applied to.

然后的问题是,如何在不完全知道 投射内容的情况下如何将项目添加/移动到ItemsSource?

The question is then how do I add/move items to the ItemsSource without knowing exactly what to cast too?

感谢您的帮助.

推荐答案

感谢帮助人员.事实证明,这要比我想的要简单得多,因为OC实现了它,所以只需要将其转换为IList即可,并且它就像一个魅力一样工作.这是可能需要的任何人的完整代码.这可以应用于由实现IList的任何集合(包括Observable Collections和常规Lists)支持的任何列表框:

Thanks for the help guys. Turns out to be much simpler then I thought, just had to cast it to an IList since OC implements it and it worked like a charm. Here is the completed code for anyone that might need it. This can be applied to any listbox that is backed by any collection implementing IList including Observable Collections and generic Lists, among others:

void ListBoxItem_Drop(object sender, DragEventArgs e)
{
    object Target = ((ListBoxItem)(sender)).DataContext;
    object Dropped = e.Data.GetData(Target.GetType());

    ListBox container = ((DependencyObject)sender).GetAncestor<ListBox>();

    int RemoveIndex = container.Items.IndexOf(Dropped);
    int TargetIndex = container.Items.IndexOf(Target);

    IList IList = (IList)container.ItemsSource;

    if (RemoveIndex < TargetIndex)
    {
        IList.Insert(TargetIndex + 1, Dropped); 
        IList.RemoveAt(RemoveIndex);
    }
    else
        if (IList.Count > RemoveIndex)
        {
            IList.Insert(TargetIndex, Dropped);
            IList.RemoveAt(RemoveIndex + 1);
        }
}

Ernie

这篇关于一般拖放ListBoxItems的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆