Переупорядочить / переместить / перетащить ListViewItems в том же элементе управления ListView в C# Windows Forms
У меня есть ListView в LargeIcon View в C# 2008 Система Windows Forms. Теперь я хотел бы переместить элемент этого ListView в том же ListView в другую позицию - назовем его "перетаскивание" или "переупорядочение элементов" или что-то еще. VB 6 способен на это и делает это автоматически в любом listView.
В C#, похоже, нет этой функции, или ее нужно было сначала кодировать. Для кодирования этого у меня нет опыта, и я не нашел ответа в своем исследовании в Интернете. Я нашел только "процедуру переопределения", которая не сработала.
Мне не нужны никакие другие элементы управления ListView (например, ObjectListView или что-то еще), и мне не нужно переопределять процедуры или создавать новый элемент управления ListView. Я хочу обработать это в элементе управления ListView, предоставленном Microsoft, как есть. Любые идеи по этому поводу. Код был бы высоко оценен, я полагаю, что я не смогу сделать это самостоятельно, если это не будет очень простой однострочник.
PS: если необходимо переместить элемент, мне нужно переместить все свойства элемента (текст, тег, ключ изображения, цвет фона, цвет переднего плана, имя, текст подсказки и т. Д.). Я понятия не имею, как это можно сделать. Я нашел один намек на это: он существует для удаления элемента (называемого .Remove()) и вставки с именем .Insert(). Но с этой информацией я все еще не могу сделать "перемещение" элементов мышью. Я думаю, что все DragEvents listView играют здесь роль, но я не знаю, как их использовать и как скопировать выбранные элементы (listView1.SelectedItems) в правильную позицию и необходимость сначала получить эту позицию.
3 ответа
Фактически, функция, о которой вы говорите, не поддерживается Winforms, а не C#. C# не имеет ничего общего с такой функцией; это функция технологии пользовательского интерфейса, а не языковая функция. Однако, чтобы решить это, у нас мало кода здесь. Поддерживает Position
свойство для каждого ListViewItem
использовать для этой цели (в LargeIcon
Посмотреть). Еще одно важное свойство AutoArrange
это должно быть установлено false
чтобы позволить Position
вступить в силу. Вот код:
ListViewItem heldDownItem;
Point heldDownPoint;
//MouseDown event handler for your listView1
private void listView1_MouseDown(object sender, MouseEventArgs e)
{
//listView1.AutoArrange = false;
heldDownItem = listView1.GetItemAt(e.X,e.Y);
if (heldDownItem != null) {
heldDownPoint = new Point(e.X - heldDownItem.Position.X,
e.Y - heldDownItem.Position.Y);
}
}
//MouseMove event handler for your listView1
private void listView1_MouseMove(object sender, MouseEventArgs e)
{
if (heldDownItem != null){
heldDownItem.Position = new Point(e.Location.X - heldDownPoint.X,
e.Location.Y - heldDownPoint.Y);
}
}
//MouseUp event handler for your listView1
private void listView1_MouseUp(object sender, MouseEventArgs e)
{
heldDownItem = null;
//listView1.AutoArrange = true;
}
ПРИМЕЧАНИЕ: как вы можете видеть, я оставил 2 строки кода с комментариями listView1.AutoArrange
там, если вы хотите reorder
вместо изменения ListViewItem
Положение вы можете раскомментировать эти строки. Я могу заметить некоторое мерцание здесь (это нормально, когда вы работаете с winforms ListView), поэтому вы должны использовать этот код (может быть помещен в конструктор формы), чтобы включить DoubleBuffered
:
typeof(Control).GetProperty("DoubleBuffered",
System.Reflection.BindingFlags.NonPublic |
System.Reflection.BindingFlags.Instance)
.SetValue(listView1, true, null);
Рабочий пример переупорядочивания перетаскиванием есть в этой статье или здесь . Предоставленный код также поддерживает метку вставки. Ниже код из статьи:
using System;
using System.Drawing;
using System.Windows.Forms;
public class ListViewInsertionMarkExample : Form
{
private ListView myListView;
public ListViewInsertionMarkExample()
{
// Initialize myListView.
myListView = new ListView();
myListView.Dock = DockStyle.Fill;
myListView.View = View.LargeIcon;
myListView.MultiSelect = false;
myListView.ListViewItemSorter = new ListViewIndexComparer();
// Initialize the insertion mark.
myListView.InsertionMark.Color = Color.Green;
// Add items to myListView.
myListView.Items.Add("zero");
myListView.Items.Add("one");
myListView.Items.Add("two");
myListView.Items.Add("three");
myListView.Items.Add("four");
myListView.Items.Add("five");
// Initialize the drag-and-drop operation when running
// under Windows XP or a later operating system.
if (OSFeature.Feature.IsPresent(OSFeature.Themes))
{
myListView.AllowDrop = true;
myListView.ItemDrag += new ItemDragEventHandler(myListView_ItemDrag);
myListView.DragEnter += new DragEventHandler(myListView_DragEnter);
myListView.DragOver += new DragEventHandler(myListView_DragOver);
myListView.DragLeave += new EventHandler(myListView_DragLeave);
myListView.DragDrop += new DragEventHandler(myListView_DragDrop);
}
// Initialize the form.
this.Text = "ListView Insertion Mark Example";
this.Controls.Add(myListView);
}
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new ListViewInsertionMarkExample());
}
// Starts the drag-and-drop operation when an item is dragged.
private void myListView_ItemDrag(object sender, ItemDragEventArgs e)
{
myListView.DoDragDrop(e.Item, DragDropEffects.Move);
}
// Sets the target drop effect.
private void myListView_DragEnter(object sender, DragEventArgs e)
{
e.Effect = e.AllowedEffect;
}
// Moves the insertion mark as the item is dragged.
private void myListView_DragOver(object sender, DragEventArgs e)
{
// Retrieve the client coordinates of the mouse pointer.
Point targetPoint =
myListView.PointToClient(new Point(e.X, e.Y));
// Retrieve the index of the item closest to the mouse pointer.
int targetIndex = myListView.InsertionMark.NearestIndex(targetPoint);
// Confirm that the mouse pointer is not over the dragged item.
if (targetIndex > -1)
{
// Determine whether the mouse pointer is to the left or
// the right of the midpoint of the closest item and set
// the InsertionMark.AppearsAfterItem property accordingly.
Rectangle itemBounds = myListView.GetItemRect(targetIndex);
if ( targetPoint.X > itemBounds.Left + (itemBounds.Width / 2) )
{
myListView.InsertionMark.AppearsAfterItem = true;
}
else
{
myListView.InsertionMark.AppearsAfterItem = false;
}
}
// Set the location of the insertion mark. If the mouse is
// over the dragged item, the targetIndex value is -1 and
// the insertion mark disappears.
myListView.InsertionMark.Index = targetIndex;
}
// Removes the insertion mark when the mouse leaves the control.
private void myListView_DragLeave(object sender, EventArgs e)
{
myListView.InsertionMark.Index = -1;
}
// Moves the item to the location of the insertion mark.
private void myListView_DragDrop(object sender, DragEventArgs e)
{
// Retrieve the index of the insertion mark;
int targetIndex = myListView.InsertionMark.Index;
// If the insertion mark is not visible, exit the method.
if (targetIndex == -1)
{
return;
}
// If the insertion mark is to the right of the item with
// the corresponding index, increment the target index.
if (myListView.InsertionMark.AppearsAfterItem)
{
targetIndex++;
}
// Retrieve the dragged item.
ListViewItem draggedItem =
(ListViewItem)e.Data.GetData(typeof(ListViewItem));
// Insert a copy of the dragged item at the target index.
// A copy must be inserted before the original item is removed
// to preserve item index values.
myListView.Items.Insert(
targetIndex, (ListViewItem)draggedItem.Clone());
// Remove the original copy of the dragged item.
myListView.Items.Remove(draggedItem);
}
// Sorts ListViewItem objects by index.
private class ListViewIndexComparer : System.Collections.IComparer
{
public int Compare(object x, object y)
{
return ((ListViewItem)x).Index - ((ListViewItem)y).Index;
}
}
}
Остерегайтесь, где вы добавляете
myListView.ListViewItemSorter = new ListViewIndexComparer();
, у меня были проблемы с производительностью при работе с большим списком. Чтобы решить эту проблему, добавьте Comparer после добавления элементов ListView.
Мы можем использовать следующий код, чтобы получить элемент, упорядоченный по позиции
SortedDictionary<Tuple<int, int>, string> points = new SortedDictionary<Tuple<int, int>, string>();
string debug1 = "", debug2 = "";
foreach (ListViewItem item in listView1.Items)
{
Tuple<int, int> tp = new Tuple<int,int>(item.Position.Y, item.Position.X);
points.Add(tp, item.Text);
debug1 += item.Text;
}
foreach (KeyValuePair<Tuple<int, int>, string> kvp in points)
{
debug2 += kvp.Value;
}
MessageBox.Show(debug1); //orignal order
MessageBox.Show(debug2); //sort by position