zoukankan      html  css  js  c++  java
  • 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 = 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功能。

  • 相关阅读:
    Java安全之JNDI注入
    Visual Studio 2019 升级16.8之后(升级.Net 5),RazorTagHelper任务意外失败
    .Net Core 3.1升级 .Net 5后出现代码错误 rzc generate exited with code 1.
    重走py 之路 ——普通操作与函数(三)
    重走py 之路 ——字典和集合(二)
    设计模式结(完结篇)
    重走py 之路 ——列表(一)
    RestfulApi 学习笔记——分页和排序(五)
    RestfulApi 学习笔记——查询与过滤还有搜索(五)
    Android开发 Error:The number of method references in a .dex file cannot exceed 64K.Android开发 Error:The number of method references in a .dex file cannot exceed 64K
  • 原文地址:https://www.cnblogs.com/max198727/p/3387805.html
Copyright © 2011-2022 走看看