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拖动子项内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论