ItemsControl 拖放

时间:2023-04-26
本文介绍了ItemsControl 拖放的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着跟版网的小编来一起学习吧!

问题描述

我有一个带有 DataTemplate 的 ItemsControl,它绑定到整数的 ObservableCollection.

I have an ItemsControl with a DataTemplate that is bound to an ObservableCollection of integers.

<ItemsControl Name="DimsContainer" ItemTemplate="{StaticResource DimensionsTemplate}">
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
   </ItemsControl.ItemsPanel>
</ItemsControl>

在 Windows 资源中:

And in the Windows Resources:

<Window.Resources>
    <DataTemplate x:Key="DimensionsTemplate" >
        <TextBlock Text="{Binding}"
                       Padding="5"
                       VerticalAlignment="Center"
                       FontSize="32"/>
    </DataTemplate>
</Window.Resources>

我正在尝试实现在 ItemsControl 中拖放项目的能力(即能够对整数重新排序).有没有人有一个简单的例子来说明如何做到这一点?我连接了 PreviewMouseMove、DragEnter 和 Drop 事件.问题是我无法弄清楚如何确定正在拖动哪个项目以及将其拖动到哪里.似乎整个 ItemsControl 都被传递到了事件中.

I'm trying to implement the ability to drag and drop items within the ItemsControl (i.e. to be able to reorder the integers). Does anyone have a simple example of how to do this? I hooked up the PreviewMouseMove, DragEnter and Drop events. The problem is that I can't figure out how to determine which item is being dragged and where it is dragged to. It seems that the entire ItemsControl gets passed into the events.

推荐答案

这是我如何做到的示例.

Here is an example how I've done it.

XAML:

<Window.DataContext>
    <local:MyViewModel />
</Window.DataContext>

<Grid>
    <ScrollViewer>
        <ListView ItemsSource="{Binding MyData}" HorizontalAlignment="Stretch" Name="listview" ScrollViewer.PanningMode="VerticalOnly">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Button Content="{Binding}"
                        Command="{Binding DataContext.MyCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}}" 
                        CommandParameter="{Binding}"
                        Margin="5 2" Width="150" Height="50"
                        FontSize="30" />
                </DataTemplate>
            </ListView.ItemTemplate>
            <ListView.Resources>
                <Style TargetType="Button">
                    <EventSetter Event="PreviewMouseMove" Handler="PreviewMouseMove" />                        
                    <EventSetter Event="Drop" Handler="Drop" />                       
                    <Setter Property="AllowDrop" Value="True" />                        
                </Style>
            </ListView.Resources>
        </ListView>
    </ScrollViewer>
</Grid>

ViewModel:

 class MyViewModel
{
    public MyViewModel()
    {
        MyCommand = new ICommandImplementation();
    }

    public ObservableCollection<string> MyData
    {
        get
        {
            return new ObservableCollection<string>(new string[]{
            "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", 
            "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", "twenty"
            });
        }
    }

    public ICommand MyCommand { get; private set; }

    private class ICommandImplementation : ICommand
    {
        public bool CanExecute(object parameter) { return true; }
        public event EventHandler CanExecuteChanged;
        public void Execute(object parameter) { System.Windows.MessageBox.Show("Button clicked! " + (parameter ?? "").ToString()); }
    }
}

事件:

 private void Drop(object sender, DragEventArgs e)
    {
        var source = e.Data.GetData("Source") as string;
        if (source != null)
        {
            int newIndex = listview.Items.IndexOf((sender as Button).Content);
            var list = listview.ItemsSource as ObservableCollection<string>;
            list.RemoveAt(list.IndexOf(source));
            list.Insert(newIndex, source);
        }
    }

    private void PreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (e.LeftButton == MouseButtonState.Pressed)
        {
            Task.Factory.StartNew(new Action(() =>
                {
                    Thread.Sleep(500);
                    App.Current.Dispatcher.BeginInvoke(new Action(() =>
                        {
                            if (e.LeftButton == MouseButtonState.Pressed)
                            {                                    
                                var data = new DataObject();
                                data.SetData("Source", (sender as Button).Content);
                                DragDrop.DoDragDrop(sender as DependencyObject, data, DragDropEffects.Move);
                                e.Handled = true;
                            }
                        }), null);
                }), CancellationToken.None);
        }           
    }

上面的例子有点复杂,因为 list 的每个项目都是一个 Button 并且在 Button click 我也得做一些动作.你的案子比较简单.

Above example is a little complex cause every item of list is a Button and on Button click I also have to do some action. Your case is relatively easy.

拖动 &Drop 可能会让许多开发人员感到困惑.但在下面是一些关键点如何做到这一点:

Drag & Drop can be confusing for many developers. But below are the some key points how to do it:

  1. 使用 PreviewMouseMove 事件实际开始拖动,并在处理程序中使用 DragDrop.DoDragDrop 事件引发 DragDrop 相关事件和 游标.sender 参数是具有在这种情况下,当前捕获的鼠标 UIElement 是被拖了.

  1. Use PreviewMouseMove event to actually start a drag and in handler use DragDrop.DoDragDrop event to raise DragDrop related events and Cursors. sender argument is the element that has captured the mouse currently in this case the UIElement that is being dragged.

使用 DragEnter &DragOver 事件,如果想要更改 Mouse 当前拖动的元素的视觉效果.发件人参数是当前拖过/的元素结束拖拽情况.

Use DragEnter & DragOver event if want to change the visual of element over which the Mouse is currently dragging. sender argument is the element that has currently dragged over / that just ended drag over situation.

使用 Drop 事件来处理被放置的元素.sender 参数是 Drop 发生的元素.

Use Drop event to handle the dropped element. sender argument is the element on which the Drop happened.

使用 DataObject 对象在这些事件之间传递信息.类的SetData 方法用于在其中添加数据.这种方法有两个参数,它们像 key-value 对一样工作.一旦设置你可以通过使用在 DragDrop 的下一个调用事件中获取此数据GetData 方法,通过传递 key 作为参数.(IE.e.Data.GetData("Source"))

Use DataObject object to pass info between these events. SetData method of the class is used to add data in this. This method has two arguments, and they work like key-value pair. Once set you can get this data in next called event of DragDrop by using GetData method by passing the key as argument. (i.e. e.Data.GetData("Source"))

这里是一个相对的帖子.

这篇关于ItemsControl 拖放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

上一篇:C# 拖动 &amp;从列表框拖放到树视图 下一篇:使用 IStream 拖放虚拟文件

相关文章