【发布时间】:2010-10-22 18:05:49
【问题描述】:
这是一个简单的过程吗?
我只是为内部工具编写一个快速的 hacky 用户界面。
我不想花太多时间在上面。
【问题讨论】:
这是一个简单的过程吗?
我只是为内部工具编写一个快速的 hacky 用户界面。
我不想花太多时间在上面。
【问题讨论】:
这是一个快速而肮脏的应用程序。基本上,我创建了一个带有按钮和 ListBox 的表单。单击按钮时,ListBox 将填充下一个 20 天的日期(必须使用某些东西来进行测试)。然后,它允许在 ListBox 中拖放以进行重新排序:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
this.listBox1.AllowDrop = true;
}
private void button1_Click(object sender, EventArgs e)
{
for (int i = 0; i <= 20; i++)
{
this.listBox1.Items.Add(DateTime.Now.AddDays(i));
}
}
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
if (this.listBox1.SelectedItem == null) return;
this.listBox1.DoDragDrop(this.listBox1.SelectedItem, DragDropEffects.Move);
}
private void listBox1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void listBox1_DragDrop(object sender, DragEventArgs e)
{
Point point = listBox1.PointToClient(new Point(e.X, e.Y));
int index = this.listBox1.IndexFromPoint(point);
if (index < 0) index = this.listBox1.Items.Count-1;
object data = e.Data.GetData(typeof(DateTime));
this.listBox1.Items.Remove(data);
this.listBox1.Items.Insert(index, data);
}
【讨论】:
晚了 7 年。但是对于任何新人,这里是代码。
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
if (this.listBox1.SelectedItem == null) return;
this.listBox1.DoDragDrop(this.listBox1.SelectedItem, DragDropEffects.Move);
}
private void listBox1_DragOver(object sender, DragEventArgs e)
{
e.Effect = DragDropEffects.Move;
}
private void listBox1_DragDrop(object sender, DragEventArgs e)
{
Point point = listBox1.PointToClient(new Point(e.X, e.Y));
int index = this.listBox1.IndexFromPoint(point);
if (index < 0) index = this.listBox1.Items.Count - 1;
object data = listBox1.SelectedItem;
this.listBox1.Items.Remove(data);
this.listBox1.Items.Insert(index, data);
}
private void itemcreator_Load(object sender, EventArgs e)
{
this.listBox1.AllowDrop = true;
}
【讨论】:
如果您从未实施拖放操作,第一次需要几个小时,想要正确完成它并且必须通读文档。尤其是用户取消操作时的即时反馈和恢复列表需要一些思考。将行为封装到可重用的用户控件中也需要一些时间。
如果您从未做过拖放操作,请查看来自 MSDN 的 drag and drop example。这将是一个很好的起点,您可能需要半天时间才能完成工作。
【讨论】:
这依赖于上面@BFree 的回答 - 感谢它提供了很多帮助。
我在尝试使用该解决方案时遇到了一个错误,因为我正在为我的列表框使用数据源。出于完整性考虑,如果您尝试直接将项目删除或添加到列表框,则会出现此错误:
// Causes error
this.listBox1.Items.Remove(data);
错误: System.ArgumentException: '设置 DataSource 属性时无法修改项目集合。'
解决方案:更新数据源本身,然后重新绑定到您的列表框。 Program.SelectedReports 是一个 BindingList。
代码:
private void listboxSelectedReports_DragDrop(object sender, DragEventArgs e)
{
// Get the point where item was dropped.
Point point = listboxSelectedReports.PointToClient(new Point(e.X, e.Y));
// Get the index of the item where the point was dropped
int index = this.listboxSelectedReports.IndexFromPoint(point);
// if index is invalid, put item at the end of the list.
if (index < 0) index = this.listboxSelectedReports.Items.Count - 1;
// Get the item's data.
ReportModel data = (ReportModel)e.Data.GetData(typeof(ReportModel));
// Update the property we use to control sorting within the original datasource
int newSortOrder = 0;
foreach (ReportModel report in Program.SelectedReports) {
// match sorted item on unique property
if (data.Id == report.Id)
{
report.SortOrder = index;
if (index == 0) {
// only increment our new sort order if index is 0
newSortOrder += 1;
}
} else {
// skip our dropped item's index
if (newSortOrder == index) {
newSortOrder += 1;
}
report.SortOrder = newSortOrder;
newSortOrder += 1;
}
}
// Sort original list and reset the list box datasource.
// Note: Tried other things, Reset(), Invalidate(). Updating DataSource was only way I found that worked??
Program.SelectedReports = new BindingList<ReportModel>(Program.SelectedReports.OrderBy(x => x.SortOrder).ToList());
listboxSelectedReports.DataSource = Program.SelectedReports;
listboxSelectedReports.DisplayMember = "Name";
listboxSelectedReports.ValueMember = "ID";
}
其他说明: BindingList 在这个命名空间下:
using System.ComponentModel;
在向列表动态添加项目时,请确保填充排序属性。我使用了一个整数字段“SortOrder”。
当您删除一个项目时,我不必担心更新 Sorting 属性,因为它只会产生一个数字间隙,这在我的情况下是可以的,YMMV。
说实话,除了 foreach 循环之外,可能还有更好的排序算法,但在我的情况下,我处理的项目数量非常有限。
【讨论】:
另一种方法是使用the list-view 控件,这是资源管理器用来显示文件夹内容的控件。它更复杂,但为您实现了项目拖动。
【讨论】: