如何使用相同的 ListView 移动组的 ListViewItem 部分代替另一个 ListViewItem?
How to move a ListViewItem part of a Group in place of another ListViewItem using the same ListView?
下面我试图移动 item4
代替 item5
,我预期的操作是将项目 4 放在 item5
之上,将项目 5 在 [=11] 下面=]:
下面我试图移动 item4 来代替 item5
,我预期的操作是 item4
位于 item5
之上,item5
位于下方item4
:
我也无法移动一个项目来代替另一个项目,有人可以帮忙吗?
我在这里留下完整的代码,包括设计:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp3
{
public partial class Form1 : Form
{
private ListView listView;
private ListViewItem currentVieItem;
public Form1()
{
InitializeComponent();
createListview();
}
public void createListview()
{
listView = new ListView();
listView.AllowDrop = true;
listView.ItemDrag += new ItemDragEventHandler(OnItemDrag);
listView.DragOver += new DragEventHandler(OnDragOver);
listView.DragDrop += new DragEventHandler(OnDragDrop);
// MY CODE HERE
ColumnHeader columnHeader = new ColumnHeader();
listView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
columnHeader});
listView.HideSelection = false;
int indexGroup = 1;
ListViewGroup group = new ListViewGroup();
for (int i = 0; i < 100; i++)
{
if (i % 5 == 0)
{
string nmGroup = $"Group {indexGroup}";
group = new ListViewGroup() { Header = nmGroup};
listView.Groups.Add(group);
indexGroup++;
}
listView.Items.Add(new ListViewItem() { Text = $"Item {i}", Group = group });
}
listView.Location = new System.Drawing.Point(12, 12);
listView.Name = "listView1";
listView.Size = new System.Drawing.Size(436, 494);
listView.TabIndex = 0;
listView.UseCompatibleStateImageBehavior = false;
listView.View = System.Windows.Forms.View.Details;
//
// columnHeader1
//
columnHeader.Text = "Items";
columnHeader.Width = 382;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(937, 600);
this.Controls.Add(listView);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
public void OnDragOver(object sender, DragEventArgs e)
{
var pos = listView.PointToClient(new Point(e.X, e.Y));
var hit = listView.HitTest(pos);
this.currentVieItem = hit.Item;
this.Text = hit.Item?.Index.ToString();
if (e.Data.GetDataPresent(typeof(ListView.SelectedListViewItemCollection)))
{
e.Effect = e.AllowedEffect;
}
}
public void OnDragDrop(object sender, DragEventArgs e)
{
if (currentVieItem == null) return;
int index = currentVieItem.Index;
this.Text = index.ToString();
if (e.Data.GetDataPresent(typeof(ListView.SelectedListViewItemCollection)))
{
if (e.Effect == DragDropEffects.Move)
{
foreach (ListViewItem current in (ListView.SelectedListViewItemCollection)e.Data.GetData(typeof(ListView.SelectedListViewItemCollection)))
{
current.Remove();
current.Group = currentVieItem.Group;
listView.Items.Insert(index, current);
index++;
}
}
}
}
public void OnItemDrag(object sender, ItemDragEventArgs e)
{
listView.DoDragDrop(listView.SelectedItems, DragDropEffects.Move);
}
}
}
虽然 ListViewItem.Group.Items.Insert() 方法按预期工作(项目插入到指定位置),但组本身不会根据分配给新项目的索引(组索引)对其项目进行排序.
项目的现有顺序优先,因此最后添加新项目。
如果您根据自己的条件为 ListView 分配自定义 ListViewItemSorter,则可以重新定义此行为,当您更改项目的顺序时。
请注意,当您将 Item 分配给 Group 时,您不需要从 ListView 或原始 Group 中删除 Item,只需将 Item 插入不同的 Group(即 [ListViewItem].Remove()
是不需要)。
您可以将拖动的项目插入到包含您正在拖动的项目的组中。
您可以删除 currentVieItem
引用,这也不是必需的。见代码。
这里没有使用 DragOver
事件处理程序(没有用)。
它可以用来显示 InsertionMark.
保留 ListView 的初始化,更改处理程序的名称:
// [...]
listView.ItemDrag += OnLVItemDrag;
listView.DragEnter += OnLVDragEnter;
listView.DragDrop += OnLVDragDrop;
// [...]
替换事件处理程序中的代码:
public void OnLVItemDrag(object sender, ItemDragEventArgs e)
{
var lv = sender as ListView;
lv.DoDragDrop(lv.SelectedItems, DragDropEffects.Move);
}
private void OnLVDragEnter(object sender, DragEventArgs e) => e.Effect = e.AllowedEffect;
public void OnLVDragDrop(object sender, DragEventArgs e)
{
var data = e.Data.GetData(typeof(ListView.SelectedListViewItemCollection)) as ListView.SelectedListViewItemCollection;
if (data is null) return;
var lv = sender as ListView;
var nearestItem = lv.HitTest(lv.PointToClient(new Point(e.X, e.Y))).Item;
if (nearestItem is null) return;
var groupIndex = nearestItem.Group.Items.IndexOf(nearestItem);
if (e.Effect == DragDropEffects.Move) {
foreach (ListViewItem item in data) {
nearestItem.Group.Items.Insert(groupIndex, item);
groupIndex++;
}
lv.ListViewItemSorter = new ListViewSorter(sortByIndex: true, useGroupIndex: true);
}
// else{} Handle other operations
}
自定义 ListViewItemSorter
对象:
此自定义对象可以根据子项的 Text
属性(默认)或项目索引或组索引对 ListView 进行排序。
using System.Collections;
class ListViewSorter : IComparer {
int columnIdx = 0;
bool indexSort = false;
bool sortGroups = false;
public ListViewSorter() { }
public ListViewSorter(int column) => columnIdx = column;
public ListViewSorter(bool sortByIndex, bool useGroupIndex) {
sortGroups = useGroupIndex;
indexSort = sortByIndex;
}
public int Compare(object lvi1, object lvi2)
{
var item1 = lvi1 as ListViewItem;
var item2 = lvi2 as ListViewItem;
if (indexSort) {
if (sortGroups && item1.Group != null && item2.Group != null) {
int idx1 = item1.Group.Items.IndexOf(item1);
int idx2 = item2.Group.Items.IndexOf(item2);
return idx1 - idx2;
}
else {
return item1.Index - item2.Index;
}
}
else {
return string.Compare(
item1.SubItems[columnIdx].Text,
item2.SubItems[columnIdx].Text);
}
}
}
这是它的工作原理:
下面我试图移动 item4
代替 item5
,我预期的操作是将项目 4 放在 item5
之上,将项目 5 在 [=11] 下面=]:
下面我试图移动 item4 来代替 item5
,我预期的操作是 item4
位于 item5
之上,item5
位于下方item4
:
我也无法移动一个项目来代替另一个项目,有人可以帮忙吗?
我在这里留下完整的代码,包括设计:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp3
{
public partial class Form1 : Form
{
private ListView listView;
private ListViewItem currentVieItem;
public Form1()
{
InitializeComponent();
createListview();
}
public void createListview()
{
listView = new ListView();
listView.AllowDrop = true;
listView.ItemDrag += new ItemDragEventHandler(OnItemDrag);
listView.DragOver += new DragEventHandler(OnDragOver);
listView.DragDrop += new DragEventHandler(OnDragDrop);
// MY CODE HERE
ColumnHeader columnHeader = new ColumnHeader();
listView.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] {
columnHeader});
listView.HideSelection = false;
int indexGroup = 1;
ListViewGroup group = new ListViewGroup();
for (int i = 0; i < 100; i++)
{
if (i % 5 == 0)
{
string nmGroup = $"Group {indexGroup}";
group = new ListViewGroup() { Header = nmGroup};
listView.Groups.Add(group);
indexGroup++;
}
listView.Items.Add(new ListViewItem() { Text = $"Item {i}", Group = group });
}
listView.Location = new System.Drawing.Point(12, 12);
listView.Name = "listView1";
listView.Size = new System.Drawing.Size(436, 494);
listView.TabIndex = 0;
listView.UseCompatibleStateImageBehavior = false;
listView.View = System.Windows.Forms.View.Details;
//
// columnHeader1
//
columnHeader.Text = "Items";
columnHeader.Width = 382;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(937, 600);
this.Controls.Add(listView);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
public void OnDragOver(object sender, DragEventArgs e)
{
var pos = listView.PointToClient(new Point(e.X, e.Y));
var hit = listView.HitTest(pos);
this.currentVieItem = hit.Item;
this.Text = hit.Item?.Index.ToString();
if (e.Data.GetDataPresent(typeof(ListView.SelectedListViewItemCollection)))
{
e.Effect = e.AllowedEffect;
}
}
public void OnDragDrop(object sender, DragEventArgs e)
{
if (currentVieItem == null) return;
int index = currentVieItem.Index;
this.Text = index.ToString();
if (e.Data.GetDataPresent(typeof(ListView.SelectedListViewItemCollection)))
{
if (e.Effect == DragDropEffects.Move)
{
foreach (ListViewItem current in (ListView.SelectedListViewItemCollection)e.Data.GetData(typeof(ListView.SelectedListViewItemCollection)))
{
current.Remove();
current.Group = currentVieItem.Group;
listView.Items.Insert(index, current);
index++;
}
}
}
}
public void OnItemDrag(object sender, ItemDragEventArgs e)
{
listView.DoDragDrop(listView.SelectedItems, DragDropEffects.Move);
}
}
}
虽然 ListViewItem.Group.Items.Insert() 方法按预期工作(项目插入到指定位置),但组本身不会根据分配给新项目的索引(组索引)对其项目进行排序.
项目的现有顺序优先,因此最后添加新项目。
如果您根据自己的条件为 ListView 分配自定义 ListViewItemSorter,则可以重新定义此行为,当您更改项目的顺序时。
请注意,当您将 Item 分配给 Group 时,您不需要从 ListView 或原始 Group 中删除 Item,只需将 Item 插入不同的 Group(即 [ListViewItem].Remove()
是不需要)。
您可以将拖动的项目插入到包含您正在拖动的项目的组中。
您可以删除 currentVieItem
引用,这也不是必需的。见代码。
这里没有使用 DragOver
事件处理程序(没有用)。
它可以用来显示 InsertionMark.
保留 ListView 的初始化,更改处理程序的名称:
// [...]
listView.ItemDrag += OnLVItemDrag;
listView.DragEnter += OnLVDragEnter;
listView.DragDrop += OnLVDragDrop;
// [...]
替换事件处理程序中的代码:
public void OnLVItemDrag(object sender, ItemDragEventArgs e)
{
var lv = sender as ListView;
lv.DoDragDrop(lv.SelectedItems, DragDropEffects.Move);
}
private void OnLVDragEnter(object sender, DragEventArgs e) => e.Effect = e.AllowedEffect;
public void OnLVDragDrop(object sender, DragEventArgs e)
{
var data = e.Data.GetData(typeof(ListView.SelectedListViewItemCollection)) as ListView.SelectedListViewItemCollection;
if (data is null) return;
var lv = sender as ListView;
var nearestItem = lv.HitTest(lv.PointToClient(new Point(e.X, e.Y))).Item;
if (nearestItem is null) return;
var groupIndex = nearestItem.Group.Items.IndexOf(nearestItem);
if (e.Effect == DragDropEffects.Move) {
foreach (ListViewItem item in data) {
nearestItem.Group.Items.Insert(groupIndex, item);
groupIndex++;
}
lv.ListViewItemSorter = new ListViewSorter(sortByIndex: true, useGroupIndex: true);
}
// else{} Handle other operations
}
自定义 ListViewItemSorter
对象:
此自定义对象可以根据子项的 Text
属性(默认)或项目索引或组索引对 ListView 进行排序。
using System.Collections;
class ListViewSorter : IComparer {
int columnIdx = 0;
bool indexSort = false;
bool sortGroups = false;
public ListViewSorter() { }
public ListViewSorter(int column) => columnIdx = column;
public ListViewSorter(bool sortByIndex, bool useGroupIndex) {
sortGroups = useGroupIndex;
indexSort = sortByIndex;
}
public int Compare(object lvi1, object lvi2)
{
var item1 = lvi1 as ListViewItem;
var item2 = lvi2 as ListViewItem;
if (indexSort) {
if (sortGroups && item1.Group != null && item2.Group != null) {
int idx1 = item1.Group.Items.IndexOf(item1);
int idx2 = item2.Group.Items.IndexOf(item2);
return idx1 - idx2;
}
else {
return item1.Index - item2.Index;
}
}
else {
return string.Compare(
item1.SubItems[columnIdx].Text,
item2.SubItems[columnIdx].Text);
}
}
}
这是它的工作原理: