WPF 的ListBox不支持很多常见的用户习惯,如在Explorer中用鼠标可以选择多项Item,并且点击已经选择的Item,按住鼠标左键可以将所有已选择Item拖拽到指定的位置。本文简单的实现了这一功能。

效果图:

拖拽1个Item

拖拽多个Item

说明:

代码下载地址:http://download.csdn.net/download/u012566751/6452323

代码中使用了两个类:

1.DragDropAdorner,用于拖拽过程中显示预览图,代码来自CSDN

2.ListBoxSelectionHelper,用于通过鼠标拖拽框选ListBoxItem,代码来自Codeproject,作者略作修改

具体操作

1.创建一个WPF工程,WpfDragMultiSelect,主界面代码如下:

<Grid><Grid.RowDefinitions><RowDefinition Height="5"/><RowDefinition Height="*"/><RowDefinition Height="5"/></Grid.RowDefinitions><Grid.ColumnDefinitions><ColumnDefinition Width="5"/><ColumnDefinition Width="50"/><ColumnDefinition Width="5"/><ColumnDefinition Width="*"/><ColumnDefinition Width="5"/></Grid.ColumnDefinitions><Grid Grid.Row="1" Grid.Column="1" Background="Black"/><GridSplitter Grid.Row="1" Grid.Column="2"ShowsPreview="True"HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/><Grid Grid.Row="1" Grid.Column="3" Background="Gray"></Grid></Grid>

2.创建一个列表,使用数据绑定方式,数据类如下:

class ListData{public int Number{get;set;}public ListData(int nNum){Number = nNum;}}

数据类只有一个公共属性Number,类型为int

主类添加代码:

List<ListData> _list = new List<ListData>();
AdornerLayer mAdornerLayer = null;
bool bIsDraging = false;public MainWindow(){InitializeComponent();for (int n = 0; n < 600; n++ ){this._list.Add(new ListData(n));}this.DataContext = _list;this.list.AllowDrop = true;this.list.QueryContinueDrag += delegate(object sender, QueryContinueDragEventArgs e){//_adornerLayer.Update();//this.list.Cursor = Cursors.Arrow;
                mAdornerLayer.Update();};}

_list作为列表数据源

bIsDraging表示数据拖拽状态

列表数据模板如下:

<DataTemplate x:Key="dt_Rectangle"><Grid Margin="10" ><Rectangle Width="50"Height="50" Fill="LightBlue" RadiusX="3" RadiusY="3"  /><TextBlock Text="{Binding Path=Number}"Foreground="White"VerticalAlignment="Center"HorizontalAlignment="Center"/><Rectangle Width="50"Height="50"Fill="Transparent"PreviewMouseDown="Rectangle_PreviewMouseDown" PreviewMouseMove="Rectangle_PreviewMouseMove" PreviewMouseUp="Rectangle_PreviewMouseUp" /></Grid></DataTemplate>

每个列表显示为一个亮蓝色(LightBlue)的正方形,在每个正方形中显示该项绑定ListData对象的Number属性。

最后一个Rectangle专门用于响应鼠标事件

在主界面中添加列表:

<ListBox x:Name="list" Background="Transparent"ItemsSource="{Binding}"ScrollViewer.HorizontalScrollBarVisibility="Disabled"loc:ListBoxSelectionHelper.MultiSelect="True"                 loc:ListBoxSelectionHelper.PreviewDrag="True" PreviewDragEnter="list_PreviewDragEnter"><ListBox.ItemTemplate><DynamicResource ResourceKey="dt_Rectangle"/></ListBox.ItemTemplate><ListBox.ItemsPanel><ItemsPanelTemplate><WrapPanel/></ItemsPanelTemplate></ListBox.ItemsPanel></ListBox>

代码:loc:ListBoxSelectionHelper.MultiSelect="True"  loc:ListBoxSelectionHelper.PreviewDrag="True" ,使用ListBoxSelectionHelper类实现鼠标拖拽框选功能

3.添加一个Grid,用于在拖拽过程中显示预览

<!--拖拽预览--><Grid Width="100"Height="100"><Grid x:Name="gridAdorner" Visibility="Hidden"><Rectangle Width="50"Height="50"Fill="LightGray"/><TextBlock x:Name="textAdorner" Text="0"VerticalAlignment="Center"HorizontalAlignment="Center" Foreground="Red" FontSize="20"></TextBlock></Grid></Grid>

4.实现数据模板dt_Rectangle中声明的事件,用以支持拖拽功能

private void Rectangle_PreviewMouseDown(object sender, MouseButtonEventArgs e){var rectangle = (FrameworkElement)sender;var rectangleViewModel = (ListData)rectangle.DataContext;ListBoxItem lstitem = this.list.ItemContainerGenerator.ContainerFromItem(rectangleViewModel) as ListBoxItem;if (lstitem.IsSelected == true){bIsDraging = true;e.Handled = true;}else{bIsDraging = false;}}private void Rectangle_PreviewMouseMove(object sender, MouseEventArgs e){if(bIsDraging){if (Mouse.LeftButton == MouseButtonState.Pressed){if (this.list.SelectedItems.Count>0){//ListBoxItem lstitem = this.list.ItemContainerGenerator.ContainerFromItem(pr) as ListBoxItem;//更新数据//MAx 2013-10-23 16:19:44this.textAdorner.Text = this.list.SelectedItems.Count.ToString();this.gridAdorner.Visibility = Visibility.Visible;DragDropAdorner adorner = new DragDropAdorner(this.gridAdorner);mAdornerLayer = AdornerLayer.GetAdornerLayer(this.list); // Window class do not have AdornerLayer
                        mAdornerLayer.Add(adorner);this.list.Cursor = Cursors.Arrow;string[] files = new string[1];DragDrop.DoDragDrop(list, new DataObject(DataFormats.FileDrop, files), DragDropEffects.Copy | DragDropEffects.Move /* | DragDropEffects.Link */);//DataObject dataObject = new DataObject(files);//System.Windows.DragDrop.DoDragDrop(this.list, dataObject, DragDropEffects.Copy);
mAdornerLayer.Remove(adorner);mAdornerLayer = null;this.gridAdorner.Visibility = Visibility.Hidden;}}}}private void Rectangle_PreviewMouseUp(object sender, MouseButtonEventArgs e){bIsDraging = false;}

分别响应PreviewMouseDown,PreviewMouseMove,PreviewMouseUp三个事件
PreviewMouseDown:判断Item是否选为已选择的Item,如果是则进入拖拽状态,标记bIsDraging,并且截断事件e.Handled = true;如果不截断,ListBox会响应点击事件,默认选择当前Item

Rectangle_PreviewMouseMove:如果当前为拖拽状态且鼠标左键按下,则开始拖拽。将gridAdorner作为拖拽预览

Rectangle_PreviewMouseUp:关闭拖拽状态

至此,已经完全实现拖拽多个Item功能。

转载于:https://www.cnblogs.com/max198727/p/3387805.html

WPF MultiSelect模式下ListBox 实现多个ListBoxItem拖拽相关推荐

  1. wpf mvvm模式下CommandParameter传递多参

    wpf mvvm模式下CommandParameter传递多参 原文:wpf mvvm模式下CommandParameter传递多参 CommandParameter一般只允许设置一次,所以如果要传递 ...

  2. swift 拖动按钮_Swift下使用UICollectionView 实现长按拖拽功能

    导读 简单用Swift写了一个collectionview的拖拽点击排序效果; 拖拽排序是新闻类的App可以说是必有的交互设计,如今日头条,网易新闻等. 效果 主要代码 手势长按移动 1.给Colle ...

  3. swift 选中长按项_Swift下使用UICollectionView 实现长按拖拽功能

    导读 简单用Swift写了一个collectionview的拖拽点击排序效果; 拖拽排序是新闻类的App可以说是必有的交互设计,如今日头条,网易新闻等. GitHub地址:https://github ...

  4. C# WPF MVVM模式下在主窗体显示子窗体并获取结果

    01 - 前言 在winform中打开一个新的子窗体很简单,直接实例化窗体并show一下就可以: Form2 f2 = new Form2();f2.Show(); 或者 Form2 f2 = new ...

  5. WPF MVVM模式下的无阻塞刷新

    MVVM模式下的无阻塞刷新的两种方法: //传统模式下的无刷新调用(主线程开新线程,新线程又调用主线程来更新UI) //第1步先在线程内部计算出需要绑定的数据 //第2步然后再使用Invoke/Beg ...

  6. C# WPF MVVM模式Prism框架下事件发布与订阅

    01 - 前言 处理同模块不同窗体之间的通信和不同模块之间不同窗体的通信,Prism提供了一种事件机制,可以在应用程序中低耦合的模块之间进行通信,该机制基于事件聚合器服务,允许发布者和订阅者之间通过事 ...

  7. C# WPF MVVM模式Caliburn.Micro框架下事件发布与订阅

    01 - 前言 处理同模块不同窗体之间的通信和不同模块之间不同窗体的通信,Caliburn提供了一种事件机制,可以在应用程序中低耦合的模块之间进行通信,该机制基于事件聚合器服务,允许发布者和订阅者之间 ...

  8. C# WPF MVVM模式Prism框架从零搭建(经典)

    01 - 前言 目前最新的PRISM的版本是8.1.97,本节以6.3.0.0 讲解,可以在Github上获取PRISM的源码. Prism Github地址:https://github.com/P ...

  9. WPF随笔(十四)--如何在MVVM模式下关闭窗口

    离上一篇WPF随笔有多久,再度编码WPF项目就有多久.机缘巧合又接下了一个开发WPF桌面程序的任务,又有机会详细研究之前一直忽略的细节. 今天就来谈谈如何在MVVM模式下关闭窗口. 什么?关闭窗口还要 ...

最新文章

  1. JavaScript系统对象
  2. 预编译 ASP.NET 网站以进行部署
  3. 2020年AI产业报告:100个岗位抢1个人,计算机视觉成最大缺口
  4. mysql5.7 cmake源码编译安装
  5. python基础包括什么-Python基础-数据类型总结归纳.
  6. Qt下Tcp传输文件
  7. Asp.net core中Migration工具使用的交流分享
  8. git提交代码的两种方法步骤
  9. ascii码值为负数_C语言编程基础学习字符型数据的ASCII码值为何是负数?
  10. 网络---协议(TCP/IP五层模型)
  11. Padavan(华硕固件) 伪固定闪讯密码.
  12. 数组之concat注意事项-不更改原数组
  13. Android 10 状态栏通知图标和下拉状态栏图标为白色问题
  14. 最新“3D版”DALL·E爆火,超快速度生成3D点云模型,OpenAI向谷歌新领域发起挑战丨开源...
  15. kafka文档(3)----0.8.2-kafka API(java版本)
  16. 首个可用于深度学习的ToF相关数据集——基于置信度的立体相机以及ToF相机深度图融合框架
  17. 有趣的跳跃(循环判断)
  18. Mbus新增主动报警功能,简单问题的波折路程。
  19. 微信公众号获取用户手机
  20. jenkins占据内存过大

热门文章

  1. 《孙子兵法》十三篇注译(15--结束语)
  2. vue vue-cli3 修改elementui的date-picker源码 引入node_modules里的element-ui后报错exports is not defined...
  3. 记一次 react 15.3.1 老项目升级到 react 16.7.0 之路
  4. 【.net 深呼吸】在运行阶段修改应用配置文件
  5. 2015-12-18 学习心得
  6. 使用MDT2013部署Win8系统之五-配置MDT服务器之添加任务序列
  7. 在SQL中使用convert函数进行日期的查询
  8. 奔四的技术人,内心都有哪些波澜?
  9. Shell命令-关机重启及注销之logout、exit
  10. JavaWeb学习之Spring框架(一)