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功能。

  • 相关阅读:
    linux上部署javaWeb项目
    Android 调试native的crash和anr
    你怎么知道你的网站K
    Win 10开门人类智慧的世界领先
    Preference如何增加在activity生命周期监听器
    智能指针模板,要管理动态分配的内存
    两分钟找到一些注意事项
    javascript---在自由落体实现
    URAL 1934 Black Spot --- 最短的简单修改
    最简单的ADABOOST人脸检测程序。COPY执行,前提是你配置OpenCV周围环境
  • 原文地址:https://www.cnblogs.com/max198727/p/3387805.html
Copyright © 2011-2022 走看看