WPF 的ListBox不支持不少常見的用戶習慣,如在Explorer中用鼠標能夠選擇多項Item,而且點擊已經選擇的Item,按住鼠標左鍵能夠將全部已選擇Item拖拽到指定的位置。本文簡單的實現了這一功能。this
效果圖:spa
拖拽1個Item.net
拖拽多個Itemcode
說明:orm
代碼下載地址:http://download.csdn.net/download/u012566751/6452323對象
代碼中使用了兩個類:blog
1.DragDropAdorner,用於拖拽過程當中顯示預覽圖,代碼來自CSDN事件
2.ListBoxSelectionHelper,用於經過鼠標拖拽框選ListBoxItem,代碼來自Codeproject,做者略做修改get
具體操做string
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: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[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功能。