ItemsControl拖放

12

我有一个ItemsControl,它使用DataTemplate绑定到一个整数的ObservableCollection。

<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都被传递到事件中。


你好。我看到了 @Golbin 提供的链接。但是这个例子是关于在两个面板之间进行拖放。实际上,我想要在一个ItemsControl中重新排序,就像你一样。请问你能帮我吗?你能把你的解决方案代码放在这里吗?或者你能给我一些指导吗?先谢谢了。 - amiry jd
@king.net,您是否仍需要与此问题相关的示例?这里有一个与listbox相关的示例 - http://stackoverflow.com/questions/36642622/rearrange-customcontrol-inside-wrappanel-in-wpf-c-sharp。如果需要,我可以尝试将其适应于数据模板... - Ilan
1个回答

15

以下是我完成此任务的示例。

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时我还需要执行一些操作。您的情况比较简单。

对于许多开发人员来说,拖放可能会让人感到困惑。但以下是如何进行拖放的一些关键点:

  1. 使用PreviewMouseMove事件来实际开始拖动,在处理程序中使用DragDrop.DoDragDrop事件来引发与DragDrop相关的事件和Cursors。在此情况下,sender参数是当前捕获鼠标的元素,即正在拖动的UIElement

  2. 如果要更改当前Mouse正在拖动的元素的可视化效果,请使用DragEnterDragOver事件。sender参数是当前拖动/刚刚结束拖动的元素。

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

  4. 使用DataObject对象在这些事件之间传递信息。使用该类的SetData方法添加数据。此方法有两个参数,并且它们的工作方式类似于key-value对。一旦设置,您可以通过在下一个调用的DragDrop事件中传递key作为参数来使用GetData方法获取此数据。(即e.Data.GetData("Source")

这里是一个相关的帖子。


谢谢你,Kylo。我一直在寻找一种更简单的拖放实现方法,并且你的帖子给了我所有必要的提示,让我在我的应用程序上成功实现了它! - HDL_CinC_Dragon

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接