WPF MultiSelect模式下ListBox 实现多个ListBoxItem拖拽
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 = ; n < ; 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>)
{
//ListBoxItem lstitem = this.list.ItemContainerGenerator.ContainerFromItem(pr) as ListBoxItem; //更新数据
//MAx 2013-10-23 16:19:44
this.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[]; 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功能。
WPF MultiSelect模式下ListBox 实现多个ListBoxItem拖拽的更多相关文章
- wpf mvvm模式下CommandParameter传递多参
原文:wpf mvvm模式下CommandParameter传递多参 CommandParameter一般只允许设置一次,所以如果要传递多参数,就要稍微处理一下.我暂时还没找到更好的方案,下面介绍的这 ...
- 告诉你吧,一套皮肤在winform与wpf开发模式下实现的界面效果同样精彩,winform界面和wpf界面。
一.同一资源: 二.先上软件界面: (1)wpf界面: 在wpf中实现这样类似web风格的软件界面就不用我多说了,在wpf实现这样的风格是很简单的,完全像网页设计一样的. (2)winform界面 在 ...
- WPF MVVM模式下的无阻塞刷新探讨
很多时候我们需要做一个工作,在一个方法体里面,读取大数据绑定到UI界面,由于长时间的读取,读取独占了线程域,导致界面一直处于假死状态.例如,当应用程序开始读取Web资源时,读取的时效是由网络链路的速度 ...
- WPF MVVM模式下ComboBox级联效果 选择第一项
MVVM模式下做的省市区的级联效果.通过改变ComboBox执行命令改变市,区. 解决主要问题就是默认选中第一项 1.首先要定义一个属性,继承自INotifyPropertyChanged接口.我这里 ...
- wpf图片查看器,支持鼠标滚动缩放拖拽
最近项目需要,要用到一个图片查看器,类似于windows自带的图片查看器那样,鼠标滚动可以缩放,可以拖拽图片,于是就写了这个简单的图片查看器. 前台代码: <Window x:Class=&qu ...
- WPF MVVM模式下路由事件
一,路由事件下三种路由策略: 1 冒泡:由事件源向上传递一直到根元素.2直接:只有事件源才有机会响应事件.3隧道:从元素树的根部调用事件处理程序并依次向下深入直到事件源.一般情况下,WPF提供的输入事 ...
- WPF MVVM模式下实现ListView下拉显示更多内容
在手机App中,如果有一个展示信息的列表,通常会展示很少一部分,当用户滑动到列表底部时,再加载更多内容.这样有两个好处,提高程序性能,减少网络流量.这篇博客中,将介绍如何在WPF ListView中实 ...
- wpf mvvm模式下的image绑定
view文件 <Image Grid.Column="2" Width="48" Height="64" Stretch=" ...
- wpf mvvm模式下 在ViewModel关闭view
本文只是博主用来记录笔记,误喷 使用到到了MVVM中消息通知功能 第一步:在需要关闭窗体中注册消息 public UserView() { this.DataContext = new UserVie ...
随机推荐
- python学习(八) 异常
8.1 什么是异常 8.2 按自己的方式出错 如何引发异常,以及创建自己的异常类型. 8.2.1 raise语句 >>> raise Exception Traceback (mos ...
- Zabbix自定义监控网站服务是否能够正常响应
监测tcp连接数文件名: /etc/zabbix/zabbix_agentd.conf.d/count_tcp.conf UserParameter=count.tcp,netstat -s|g ...
- 固定容器内任意个div填充算法
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- 第二章 MySQL的安装与配置(待续)
·······
- C++中的explicit关键字 - 抑制隐式转换(转)
在C++程序中很少有人去使用 explicit 关键字,不可否认,在平时的实践中确实很少能用的上.再说C++的功能强大,往往一个问题可以利用好几种C++特性去解决.但稍微留心一下就会发现现有的MFC库 ...
- 搜索——深度优先搜索(DFS)
设想我们现在身处一个巨大的迷宫中,我们只能自己想办法走出去,下面是一种看上去很盲目但实际上会很有效的方法. 以当前所在位置为起点,沿着一条路向前走,当碰到岔道口时,选择其中一个岔路前进.如果选择的这个 ...
- 【转】OpenGL随笔(1)—— mipmap 详解
注:本文使用的所有 OpenGL 函数来自 OpenGL 4.5,优先使用 DSA. 使用 mipmap 时,OpenGL 根据被映射对象的大小(单位是像素),自动决定使用纹理图的哪个分辨率级别.mi ...
- MySQL中TRUNCATE和ROUND函数的用法
一.TRUNCATE(expr, int_expr)用法 TRUNCATE函数将expr按照int_expr长度在小数点后按照位数直接进行截取. 实例: ); 输出结果:200.1256 二.ROUN ...
- linux驱动模块编译(初学者)
inux 模块编译步骤(转) 本文将直接了当的带你进入linux的模块编译.当然在介绍的过程当中,我也会添加一些必要的注释,以便初学者能够看懂.之所以要写这篇文章,主要是因为从书本上学的话,可能要花更 ...
- 用Python+Django在Eclipse环境下开发web网站
一.创建一个项目如果这是你第一次使用Django,那么你必须进行一些初始设置.也就是通过自动生成代码来建立一个Django项目--一个Django项目的设置集,包含了数据库配置.Django详细选项设 ...