[英]Custom Sort a ListBox in C# Visual Studio
I'll start by giving an example cause it will be easier.我将从举一个例子开始,因为它会更容易。
Lets say I have a ListBox that's named "lbDestinations" and I have a class for that listbox called Destination.假设我有一个名为“lbDestinations”的列表框,并且我有一个名为 Destination 的列表框的 class。
Destination.cs目的地.cs
public class Destination
{
public string Name { get; set; }
public int Distance { get; set; }
public int Price { get; set; }
public Destination(string name, int distance, int price)
{
Name = name;
Distance = distance;
Price = price;
}
public override string ToString()
{
return string.Format("{0} {1} km {2} $", Name, Distance, Price);
}
}
Now I want to add destinations with a name, the distance to that location and the price for that trip.现在我想添加带有名称、到该位置的距离和该行程价格的目的地。 Lets have a couple destinations added for examples and stuff..
让我们为示例和内容添加几个目的地..
London 100 km 200 $
Berlin 400 km 800 $
Paris 200 km 400 $
Madrid 150 km 300 $
Now if I have all those in that order in the ListBox and I do lbDestinations.Sorted it will Sort them alphabetically, but I don't want that..现在,如果我在 ListBox 中按顺序排列所有这些,并且我执行 lbDestinations.Sorted 它将按字母顺序对它们进行排序,但我不希望这样..
I want to sort them by the distance or the price.. The output has to be "Name Distance Price"我想按距离或价格对它们进行排序。output 必须是“名称距离价格”
I tried a couple things but none of them worked我尝试了几件事,但没有一个奏效
Instead of adding items to the listbox one by one, you can assign a collection to the DataSource
of the listbox.您可以将一个集合分配给列表框的
DataSource
,而不是将项目一个一个地添加到列表框。 This enables you to apply a custom sort to the collection.这使您能够对集合应用自定义排序。
Eg例如
var destinations = new List<Destination>();
destinations.Add(new Desination { Name = "London", Distance = 100, Price = 200 });
...
destinations.Sort( (a, b) => a.Price.CompareTo(b.Price) );
lbDestinations.DataSource = null; // Ensures the listbox refreshes.
lbDestinations.DataSource = destinations;
You can also use LINQ to sort by more than one column:您还可以使用 LINQ 按多列排序:
var destinations = source
.OrderBy(d => d.Price)
.ThenBy(d => d.Name)
.ToList();
The accepted answer is excellent, but I'd be remiss if I didn't mention how DataGridView
might save you a lot of legwork by automatically configuring itself based on your Destination
class.接受的答案非常好,但如果我没有提到
DataGridView
如何通过根据您的Destination
class 自动配置自身来为您节省大量跑腿工作,那我就是失职了。
I have a class [...] called Destination.
我有一个名为 Destination 的 class [...]。 The output has to be "Name Distance Price".
output 必须是“Name Distance Price”。
public class Destination
{
[ReadOnly(true)]
public string Name { get; set; } = string.Empty;
[ReadOnly(true)]
public int Distance { get; set; }
[ReadOnly(false)]
public decimal Price { get; set; }
public override string ToString() =>
string.Format($"{Name} {Distance} km {Price} $");
}
I want to sort them by the distance or the price.
我想按距离或价格对它们进行排序。
Implementation where consecutive clicks on same header alternates low-to-high or high-to-low.连续点击相同的 header 交替从低到高或从高到低的实现。
private void sortByHeader(object? sender, DataGridViewCellMouseEventArgs e)
{
Destination[] tmp;
if (!e.ColumnIndex.Equals(-1))
{
var column = dataGridView.Columns[e.ColumnIndex].Name;
if (column.Equals(_prevColumn))
{
_highToLow = !_highToLow;
}
else
{
_highToLow = false;
_prevColumn = column;
}
switch (column)
{
case nameof(Destination.Name):
tmp = _highToLow ?
Destinations.OrderByDescending(_ => _.Name).ToArray() :
Destinations.OrderBy(_ => _.Name).ToArray();
break;
case nameof(Destination.Distance):
tmp = _highToLow ?
Destinations.OrderByDescending(_ => _.Distance).ToArray() :
Destinations.OrderBy(_ => _.Distance).ToArray();
break;
case nameof(Destination.Price):
tmp = _highToLow ?
Destinations.OrderByDescending(_ => _.Price).ToArray() :
Destinations.OrderBy(_ => _.Price).ToArray();
break;
default:
return;
}
Destinations.Clear();
foreach (var destination in tmp)
{
Destinations.Add(destination);
}
}
}
string? _prevColumn = null;
bool _highToLow = false;
Auto-Generate Columns自动生成列
The method that loads the main form configures the DataGridView
using the Destination
class as a template and attaches the dataGridView.ColumnHeaderMouseClick
event to sort the data.加载主窗体的方法使用
Destination
class 作为模板配置DataGridView
,并附加dataGridView.ColumnHeaderMouseClick
事件以对数据进行排序。 The DataSource
of the data grid is set to Destinations
which is a BindingList<Destination>
.数据网格的
DataSource
设置为Destinations
,这是一个BindingList<Destination>
。
public partial class MainForm : Form
{
public MainForm() =>InitializeComponent();
private readonly BindingList<Destination> Destinations= new BindingList<Destination>();
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
dataGridView.RowTemplate.Height = 60;
// Add destinations interactively?
dataGridView.AllowUserToAddRows= false;
dataGridView.DataSource= Destinations;
#region F O R M A T C O L U M N S
Destinations.Add(new Destination()); // <= Auto-generate columns
dataGridView.Columns[nameof(Destination.Name)].AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
dataGridView.Columns[nameof(Destination.Distance)].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dataGridView.Columns[nameof(Destination.Price)].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
dataGridView.Columns[nameof(Destination.Price)].DefaultCellStyle.Format = "F2";
Destinations.Clear();
#endregion F O R M A T C O L U M N S
dataGridView.ColumnHeaderMouseClick += sortByHeader;
addDestinationsToExample();
}
.
.
.
}
Now [...] add destinations with a name, the distance to that location and the price...
现在 [...] 添加带有名称、到该位置的距离和价格的目的地...
private void addDestinationsToExample()
{
Destinations.Add(new Destination
{
// * Had to make the Price sort different from Distance sort!
Name = "London - VIP",
Distance= 100,
Price= 1200,
});
Destinations.Add(new Destination
{
Name = "Berlin",
Distance= 400,
Price= 800,
});
Destinations.Add(new Destination
{
Name = "Paris",
Distance= 200,
Price= 400,
});
Destinations.Add(new Destination
{
Name = "Madrid",
Distance= 150,
Price= 300,
});
}
I hope this adds to your toolbox of possible ways to achieve your objective.我希望这会增加您实现目标的可能方法的工具箱。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.