我有一个ListView(WinForms),我想在其中单击按钮上下移动项目.要移动的项目是被检查的项目.因此,如果选择第2,6和9项,当我按下按钮向上移动时,它们将变为1,5和8,并且这些位置上的项目向下移动一步.
我觉得我已经让这个变得不必要地变得复杂了,你可以在下面看到.每个ListViewItem的第二个SubItem是一个数字,代表它在列表中的位置(从1开始).
我责怪以下代码缺乏睡眠和咖啡,但如果你能想出一个更简单的方法来完成这个任务,我将感激不尽.
private void sourceMoveUpButton_Click(object sender, EventArgs e)
{
List<Int32> affectedNumbers = new List<Int32>();
bool foundNonChecked = false;
List<KeyValuePair<int, ListViewItem>> newList = new List<KeyValuePair<int, ListViewItem>>();
foreach (ListViewItem item in this.sourceListView.CheckedItems)
{
int newNum = int.Parse(item.SubItems[1].Text) - 1;
if (newNum >= 1)
{
foreach (ListViewItem testItem in this.sourceListView.Items)
{
if (int.Parse(testItem.SubItems[1].Text) == newNum && !testItem.Checked)
{
foundNonChecked = true;
}
}
if (foundNonChecked)
{
item.SubItems[1].Text = newNum.ToString();
affectedNumbers.Add(newNum);
}
}
}
foreach (ListViewItem item in this.sourceListView.Items)
{
int num = int.Parse(item.SubItems[1].Text);
if (affectedNumbers.Contains(num) && !item.Checked)
{
item.SubItems[1].Text = (num + affectedNumbers.Count).ToString();
}
newList.Add(new KeyValuePair<int, ListViewItem>(int.Parse(item.SubItems[1].Text), item));
item.Remove();
}
newList.Sort((firstPair, secondPair) =>
{
return firstPair.Key.CompareTo(secondPair.Key);
}
);
foreach (KeyValuePair<int, ListViewItem> pair in newList)
{
this.sourceListView.Items.Add(pair.Value);
}
}
Run Code Online (Sandbox Code Playgroud)
编辑 我已将其缩短为以下内容:
foreach (ListViewItem item in this.sourceListView.CheckedItems)
{
if (item.Index > 0)
{
int newIndex = item.Index - 1;
this.sourceListView.Items.RemoveAt(item.Index);
this.sourceListView.Items.Insert(newIndex, item);
}
}
int index = 1;
foreach (ListViewItem item in this.sourceListView.Items)
{
item.SubItems[1].Text = index.ToString();
index++;
}
Run Code Online (Sandbox Code Playgroud)
但现在,如果我选择两个最顶级的项目(或类似的),当我点击按钮向上移动时,它们将切换到位.
第二次编辑 所有内容都适用于向上移动,具体如下:
if (this.sourceListView.CheckedItems[0].Index != 0)
{
this.sourceListView.BeginUpdate();
foreach (ListViewItem item in this.sourceListView.CheckedItems)
{
if (item.Index > 0)
{
int newIndex = item.Index - 1;
this.sourceListView.Items.RemoveAt(item.Index);
this.sourceListView.Items.Insert(newIndex, item);
}
}
this.updateListIndexText();
this.sourceListView.EndUpdate();
}
Run Code Online (Sandbox Code Playgroud)
但对于向下运动,我似乎无法做到正确:
if (this.sourceListView.CheckedItems[this.sourceListView.CheckedItems.Count - 1].Index < this.sourceListView.Items.Count - 1)
{
this.sourceListView.BeginUpdate();
foreach (ListViewItem item in this.sourceListView.CheckedItems)
{
if (item.Index < this.sourceListView.Items.Count - 1)
{
int newIndex = item.Index + 1;
this.sourceListView.Items.RemoveAt(item.Index);
this.sourceListView.Items.Insert(newIndex, item);
}
}
this.updateListIndexText();
this.sourceListView.EndUpdate();
}
Run Code Online (Sandbox Code Playgroud)
它适用于移动单个项目,但是当我选择多个项目时,它不会.
Jas*_*rke 13
尝试这样的事情:
foreach (ListViewItem lvi in sourceListView.SelectedItems)
{
if (lvi.Index > 0)
{
int index = lvi.Index - 1;
sourceListView.Items.RemoveAt(lvi.Index);
sourceListView.Items.Insert(index, lvi);
}
}
Run Code Online (Sandbox Code Playgroud)
基本上只是移除项目然后将其插入到以前的位置.ListView会在插入后自动处理重新排列顺序中的项目,因此不必担心.
编辑:
两个最顶层的项目交换的原因是顶部项目永远不会移动(即我没有实现wrap-around移动.但是,第二个项目可以自由移动,因此进入列表的顶部.
要解决此问题,您可以执行以下两项操作之一:
- 实施环绕式重组(即顶部项目到底)
- 如果选择了顶部项目,则阻止任何移动(检查listview.Items [0] .Selected)
至于文本的重做,只需在原始循环中执行.
环绕式实施:
foreach (ListViewItem lvi in sourceListView.SelectedItems)
{
int index = lvi.Index > 0 ? lvi.Index - 1 : sourceListView.Items.Count - 1;
sourceListView.Items.RemoveAt(lvi.Index);
sourceListView.Items.Insert(index, lvi);
if (index != sourceListView.Items.Count - 1) //not a wraparound:
{
//just swap the indices over.
sourceListView.Items[index + 1].SubItems[1].Text = (index + 1).ToString();
lvi.SubItems[1].Text = index.ToString();
}
else //item wrapped around, have to manually update all items.
{
foreach (ListViewItem lvi2 in sourceListView.Items)
lvi2.SubItems[1].Text = lvi2.Index.ToString();
}
}
Run Code Online (Sandbox Code Playgroud)
静态助手实现,没有环绕:
private enum MoveDirection { Up = -1, Down = 1 };
private static void MoveListViewItems(ListView sender, MoveDirection direction)
{
int dir = (int)direction;
int opp = dir * -1;
bool valid = sender.SelectedItems.Count > 0 &&
((direction == MoveDirection.Down && (sender.SelectedItems[sender.SelectedItems.Count - 1].Index < sender.Items.Count - 1))
|| (direction == MoveDirection.Up && (sender.SelectedItems[0].Index > 0)));
if (valid)
{
foreach (ListViewItem item in sender.SelectedItems)
{
int index = item.Index + dir;
sender.Items.RemoveAt(item.Index);
sender.Items.Insert(index, item);
sender.Items[index + opp].SubItems[1].Text = (index + opp).ToString();
item.SubItems[1].Text = (index).ToString();
}
}
}
Run Code Online (Sandbox Code Playgroud)
例:
MoveListViewItems(sourceListView, MoveDirection.Up);
MoveListviewItems(sourceListview, MoveDirection.Down);
Run Code Online (Sandbox Code Playgroud)