c# - ItemsControl 拖放

标签 c# wpf drag-and-drop itemscontrol

我有一个 ItemsControl,它带有一个绑定(bind)到整数 ObservableCollection 的 DataTemplate。

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

在 Windows 资源中:

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

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

最佳答案

这是我如何完成的示例。

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>

View 模型:

 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 并且在 Buttonclick 我也要做一些 Action 。 你的情况相对简单。

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

  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.

  2. 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.

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

  4. 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"))

Here是相关帖子。

关于c# - ItemsControl 拖放,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3534958/

相关文章:

c# - 如何向现有 Winforms 控件添加属性

c# - 来自 WCF 服务的方法未显示在客户端应用程序中

javascript - 我可以使用 HTML5 通过单个文件拖放多个文件吗?

javascript - pixi js : drag and drop circle

android - 将 ListView 的列表项拖放到另一个 ListView 的列表项

c# - 使用具有单个 DbContext 和 Entites 的多个数据库并在运行时生成 Conn String

c# - Ajax 调用 Web API 方法

wpf - 仅适用于 VS 设计 View 的 Blend 中的 UnresolvedAssemblyException - 在 VS 设计 View 中工作正常

wpf - ActualWidth 作为 From WPF 动画的值

wpf - 无法在 WPF TextBlock 中获取垂直滚动条