DataView.Sort - больше, чем просто asc / desc (нужна пользовательская сортировка) - PullRequest
13 голосов
/ 24 февраля 2009

У меня есть отчет, созданный из набора данных. Набор данных использует свойство Sort для упорядочения данных. Я знаю, что могу создать выражение сортировки следующим образом:

"field desc, field2 asc"

Но сейчас мне нужен способ пользовательской сортировки. В SQL я могу выполнить пользовательскую сортировку, выполнив что-то вроде этого:

order by 
    case when field = 'Some Value' then 0 end
    case when field = 'Another Value' then 1 end

Чтобы в основном переопределить мой вид (то есть, Некоторое Значение предшествует другому Значение).

Можно ли сделать что-то подобное в качестве выражения сортировки для DataView?

Ответы [ 5 ]

17 голосов
/ 24 февраля 2009

Ладно, я просто очень быстро это сделал и не выполнил всю необходимую обработку ошибок и проверку нуля, но это должно дать вам представление и должно быть достаточно для начала работы:

public static class DataTableExtensions
{
    public static DataView ApplySort(this DataTable table, Comparison<DataRow> comparison)
    {

        DataTable clone = table.Clone();
        List<DataRow> rows = new List<DataRow>();
        foreach (DataRow row in table.Rows)
        {
            rows.Add(row);    
        }

        rows.Sort(comparison);

        foreach (DataRow row in rows)
        {
            clone.Rows.Add(row.ItemArray);
        }

        return clone.DefaultView;
    }


}

Использование:

    DataTable table = new DataTable();
    table.Columns.Add("IntValue", typeof(int));
    table.Columns.Add("StringValue");

    table.Rows.Add(11, "Eleven");
    table.Rows.Add(14, "Fourteen");
    table.Rows.Add(10, "Ten");
    table.Rows.Add(12, "Twelve");
    table.Rows.Add(13, "Thirteen");

// Сортировка по StringValue:

 DataView sorted = table.ApplySort((r, r2) =>
        {
            return ((string)r["StringValue"]).CompareTo(((string)r2["StringValue"]));
        });

Результат:

11 Одиннадцать

14 Четырнадцать

10 Тен

13 Тринадцать

12 Двенадцать

// Сортировка по IntValue:

DataView sorted = table.ApplySort((r, r2) =>
            {
                return ((int)r["IntValue"]).CompareTo(((int)r2["IntValue"]));
            });

Результат:

10 Десять

11 Одиннадцать

13 Тринадцать

12 Двенадцать

14 Четырнадцать

РЕДАКТИРОВАТЬ: изменил его на метод расширения.

Теперь в вашей лямбде (или вы можете создать полноценный метод сравнения) вы можете выполнять любые виды логики сортировки, которая вам нужна. Помните, что -1 меньше, 0 равно, а 1 больше.

16 голосов
/ 25 февраля 2009

Мне нравится ответ BFree, хотя я бы беспокоился о том, что мой код в итоге обновит клонированную таблицу, а не реальную. (Я не продумал это достаточно, чтобы понять, действительно ли это проблема, если вы используете только метод расширения в DataView.)

Вы можете сделать это на исходном DataTable, добавив к нему вычисленное DataColumn (используя свойство Expression), а затем отсортировав его значение.

В вашем случае это будет что-то вроде:

DataColumn c = myTable.Columns.Add("Sort", typeof(int));
c.Expression = "iif(field='SomeValue', 0, iif(field='AnotherValue', 1, 2))";

который сортирует SomeValue первый, AnotherValue второй и все остальное после этого.

5 голосов
/ 11 мая 2012

Я знаю, что этот пост немного старше, но я немного изменил его, внедрив IComparable. В этом примере я хотел отсортировать по версии (в формате 0.0.0.0 в виде строки).

Вот класс управления версиями, который реализует IComparable:

public class Versioning : IComparable {
    string _version;

    int _major;
    public int Major { 
        get { return (_major); } 
        set { _major = value; } 
    }

    int _minor;
    public int Minor {
        get { return (_minor); }
        set { _minor = value; }
    }

    int _beta;
    public int Beta {
        get { return (_beta); }
        set { _beta = value; }
    }

    int _alpha;
    public int Alpha {
        get { return (_alpha); }
        set { _alpha = value; }
    }

    public Versioning(string version) {
        _version = version;

        var splitVersion = SplitVersion();
        if (splitVersion.Length < 4) {
            Major = Minor = Beta = Alpha = 0;
        }

        if (!int.TryParse(splitVersion[0], out _major)) _major = 0;
        if (!int.TryParse(splitVersion[1], out _minor)) _minor = 0;
        if (!int.TryParse(splitVersion[2], out _beta)) _beta = 0;
        if (!int.TryParse(splitVersion[3], out _alpha)) _alpha = 0;
    }

    string[] SplitVersion() {
        return (_version.Split('.'));
    }

    int GetCompareTo(Versioning versioning) {
        var greater = -1;
        var equal = 0;
        var less = 1;

        if (Major > versioning.Major) return (greater);
        if (Major < versioning.Major) return (less);
        if (Minor > versioning.Minor) return (greater);
        if (Minor < versioning.Minor) return (less);
        if (Beta > versioning.Beta) return (greater);
        if (Beta < versioning.Beta) return (less);
        if (Alpha > versioning.Alpha) return (greater);
        if (Alpha < versioning.Alpha) return (less);

        return (equal);
    }

    public int CompareTo(Versioning versioning) {
        return (GetCompareTo(versioning));
    }

    public override string ToString() {
        return (_version);
    }

    public int CompareTo(object obj) {
        if (obj == null) return (1);
        return (GetCompareTo((Versioning)obj));
    }
}

И когда вы добавляете столбец в таблицу, вместо добавления Version в виде строки, вы добавляете ее как класс Versioning:

_table.Columns.Add("Version", typeof(Versioning));
_view = new View(_table);

А потом сортируй нормально:

_view.Sort = "Version";
1 голос
/ 24 февраля 2009

Вы можете использовать оператор if или switch, чтобы получить аналогичную функциональность оператору select case:

            if (Something == "1")
                MyView.Sort = "Field1 ASC";
            else
                MyView.Sort = "Field2 ASC";

OR

            switch (MyProperty)
            {
                case 1:
                    MyView.Sort = "Field1 ASC";
                    break;
                case 2:
                    MyView.Sort = "Field2 ASC";
                    break;
                default:
                    MyView.Sort = "Field3 ASC";
                    break;
            }
1 голос
/ 24 февраля 2009

Я так не думаю. Однако вы можете изменить свой SQL, чтобы он возвращал столбец «CustomSort», который является результатом вашего оператора case:

select
    (case when f = 'a' then 0 else 1 end) as CustomSort
from MyTable
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...