WPF 實作 ListBox 拖動子項
控制項名:WPFListBoxItemDrag
作 者:WPFDevelopersOrg - 驚鏵
源碼:如下
框架支持
.NET4 至 .NET8
;
Visual Studio 2022
;
XAML 部份:
1)新增
MainWindow.xaml
程式碼如下:
Grid
定義兩列。
第一列
ListBox
控制項,命名
ListBoxStart
,原數據被拖動者。
Canvas
畫布,用於在拖動過程中呈獻拖動項。
第二列
ListBox
控制項,命名
ListBoxEnd
,用於接收拖動者。
<wd:Window
x: class="WPFListBoxItemDrag.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WPFListBoxItemDrag"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wd="https://github.com/WPFDevelopersOrg/WPFDevelopers"
Title="WPF開發者 - ListBoxItemDrag"
Width="800"
Height="450"
WindowStartupLocation="CenterScreen"
mc:Ignorable="d">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox
x:Name="ListBoxStart"
AllowDrop="True"
BorderThickness="1"
ItemsSource="{Binding ItemsA}"
PreviewMouseLeftButtonDown="ListBoxStart_PreviewMouseLeftButtonDown"
PreviewMouseLeftButtonUp="ListBoxStart_PreviewMouseLeftButtonUp"
PreviewMouseMove="ListBoxStart_PreviewMouseMove" />
<Canvas
x:Name="DragCanvas"
Grid.ColumnSpan="2"
Panel.ZIndex="1000" />
<ListBox
x:Name="ListBoxEnd"
Grid.Column="1"
AllowDrop="True"
Drop="ListBoxEnd_Drop"
ItemsSource="{Binding ItemsB}" />
</Grid>
</wd:Window>
CSharp 部份:
2)新增
MainWindow.xaml.cs
程式碼如下:
ItemsA
和
ItemsB
是
ObservableCollection<string>
,分別用於儲存
ListBoxStart
和
ListBoxEnd
中的項。
ListBoxStart_PreviewMouseLeftButtonDown
方法處理當在
ListBoxStart
按下滑鼠左鍵時的
Item
數據,標記拖放操作的開始。
FindVisualParent
在可視樹中尋找元素。
GetListBoxItemData
獲取選中項
ListBoxItem
的數據。
ListBoxStart_PreviewMouseLeftButtonUp
處理當在
ListBoxStart
釋放滑鼠左鍵的事件執行實際的拖放操作。
ListBoxStart_PreviewMouseMove
處理當在
ListBoxStart
移動滑鼠時的事件在拖動過程中更新拖動的位置。
ListBoxEnd_Drop
處理當將
ListBoxStart
拖動項放到
ListBoxEnd
的事件,將拖動項添加到
ListBoxEnd
的資料來源中。
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
namespaceWPFListBoxItemDrag
{
///<summary>
/// Interaction logic for MainWindow.xaml
///</summary>
publicpartial classMainWindow
{
privatebool isDragging;
private ListBoxItem item;
private ListBoxItem dragItem;
privateobject data;
public ObservableCollection<string> ItemsA { get; set; }
public ObservableCollection<string> ItemsB { get; set; }
publicMainWindow()
{
InitializeComponent();
DataContext = this;
ItemsA = new() { "WPFDevelopersOrg", "WPFDevelopers", "WPF開發者", "ListBox", "ListBoxItem" };
ItemsB = new ObservableCollection<string>();
}
privatevoidListBoxStart_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
data = GetListBoxItemData(ListBoxStart, e.GetPosition(ListBoxStart));
item = FindVisualParent<ListBoxItem>((DependencyObject)e.OriginalSource);
if (item != null)
isDragging = true;
}
private T FindVisualParent<T>(DependencyObject obj) where T : DependencyObject
{
while (obj != null)
{
if (obj is T)
return (T)obj;
obj = VisualTreeHelper.GetParent(obj);
}
returnnull;
}
privateobjectGetListBoxItemData(ListBox source, Point point)
{
var element = source.InputHitTest(point) as UIElement;
if (element != null)
{
var data = DependencyProperty.UnsetValue;
while (data == DependencyProperty.UnsetValue)
{
data = source.ItemContainerGenerator.ItemFromContainer(element);
if (data == DependencyProperty.UnsetValue)
element = VisualTreeHelper.GetParent(element) as UIElement;
if (element == source)
returnnull;
}
if (data != DependencyProperty.UnsetValue)
return data;
}
returnnull;
}
privatevoidListBoxStart_PreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (data != null)
DragDrop.DoDragDrop(ListBoxStart, data, DragDropEffects.Move);
isDragging = false;
if (dragItem != null)
{
DragCanvas.Children.Remove(dragItem);
dragItem = null;
}
}
privatevoidListBoxStart_PreviewMouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
if (dragItem == null)
{
dragItem = new ListBoxItem
{
Content = item.Content,
Width = item.ActualWidth,
Height = item.ActualHeight,
Background = Brushes.Gray,
ContentTemplate = item.ContentTemplate,
ContentTemplateSelector = item.ContentTemplateSelector,
style = item. style,
Padding = item.Padding,
Opacity = .5,
IsHitTestVisible = false,
};
DragCanvas.Children.Add(dragItem);
}
var mousePos = e.GetPosition(DragCanvas);
Canvas.SetLeft(dragItem, mousePos.X - dragItem.ActualWidth / 2);
Canvas.SetTop(dragItem, mousePos.Y - dragItem.ActualHeight / 2);
}
}
privatevoidListBoxEnd_Drop(object sender, DragEventArgs e)
{
if (e.Data.GetDataPresent(typeof(string)))
{
var data = e.Data.GetData(typeof(string)).ToString();
ItemsB.Add(data);
ItemsA.Remove(data.ToString());
}
}
}
}