WPF MultiSelect模式下ListBox 實現多個ListBoxItem拖拽

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

相關文章
相關標籤/搜索