基于WPF实现ListBox拖动子项

 更新时间:2024年04月02日 10:01:31   作者:WPF开发者  
这篇文章主要为大家详细介绍了如何基于WPF实现ListBox拖动子项效果,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考下
(福利推荐:【腾讯云】服务器最新限时优惠活动,云服务器1核2G仅99元/年、2核4G仅768元/3年,立即抢购>>>:9i0i.cn/qcloud

(福利推荐:你还在原价购买阿里云服务器?现在阿里云0.8折限时抢购活动来啦!4核8G企业云服务器仅2998元/3年,立即抢购>>>:9i0i.cn/aliyun

WPF 实现 ListBox 拖动子项

框架支持.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;

namespace WPFListBoxItemDrag
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow 
    {
        private bool isDragging;
        private ListBoxItem item;
        private ListBoxItem dragItem;
        private object data;
        public ObservableCollection<string> ItemsA { get; set; }
        public ObservableCollection<string> ItemsB { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
            ItemsA = new() { "WPFDevelopersOrg", "WPFDevelopers", "WPF开发者", "ListBox", "ListBoxItem" };
            ItemsB = new ObservableCollection<string>();
        }

        private void ListBoxStart_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);
            }
            return null;
        }

        private object GetListBoxItemData(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)
                        return null;
                }
                if (data != DependencyProperty.UnsetValue)
                    return data;
            }
            return null;
        }

        private void ListBoxStart_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;
            }
        }

        private void ListBoxStart_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);
            }
        }

        private void ListBoxEnd_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());
            }
        }
    }
}

效果图

到此这篇关于基于WPF实现ListBox拖动子项的文章就介绍到这了,更多相关WPF ListBox拖动子项内容请搜索程序员之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持程序员之家!

相关文章

最新评论

?


http://www.vxiaotou.com