简体   繁体   English

在 C# Visual Studio 中自定义排序列表框

[英]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.

 
粤ICP备18138465号  © 2020-2025 STACKOOM.COM