2009-02-24 9 views
12

Mam raport zbudowany na podstawie zestawu danych. Zestaw danych wykorzystuje właściwość Sortuj do porządkowania danych. Wiem, że mogę stworzyć wyrażenie sortowania tak:DataView.Sort - więcej niż tylko asc/desc (potrzebujesz niestandardowego sortowania)

„desc pola, Pole2 ASC”

Ale co muszę teraz jest sposób, aby zrobić własny rodzaju. W SQL, mogę wykonać niestandardowy rodzaj robiąc coś takiego:

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

w zasadzie ponownie zdefiniować mój rodzaj (to jakaś wartość jest przed inną wartość).

Czy można zrobić coś podobnego, jak wyrażenie sortowania przeciwko DataView?

Odpowiedz

15

Ok, ja po prostu bita to się bardzo szybko, a nie robić wszystko neccessary obsługę błędów i sprawdzanie wartości null, ale powinno dać wyobrażenie i powinny być enou gh możesz zacząć:

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; 
    } 


} 

Zastosowanie:

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"); 

// Sortuj według StringValue:

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

Wynik:

11 Jedenaście

14 Czternaście

10 Dziesięć

13 Trzynaście

12 Dwunastu

// Sortuj według intValue:

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

Wynik:

10 Dziesięć

11 Jedenaście

13 Trzynaście

12 Dwunastu

14 Czternaście

EDIT: Zmieniono go metodę rozszerzenia.

Teraz w Twojej Lambda (lub można stworzyć pełnowartościowy metodę porównania) można zrobić wszelkiego rodzaju niestandardowych logiki sortowania, które potrzebujesz. Pamiętaj, że -1 jest mniejsze niż, 0 jest równe, a 1 jest większe niż.

+5

Jestem ci winien piwo. – Orestes

+0

Świetna odpowiedź. Potrzebowałem tylko odrobiny ulepszenia w odniesieniu do dwukierunkowego sortowania i wiązania widoku z powrotem do siatki. – tys

1

Nie sądzę. Można jednak zmienić ty SQL, aby powrócić do „CustomSort” kolumny, która jest wynikiem wyciągu koperty:

select 
    (case when f = 'a' then 0 else 1 end) as CustomSort 
from MyTable 
+0

to możliwe rozwiązanie; Mam nadzieję, że nie będę musiał go używać, ponieważ oznaczałoby to edycję kodu SQL z ponad 20 raportów. – bugfixr

1

można używać if lub switch komunikatu, aby uzyskać podobną funkcjonalność do select case:

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

lUB

  switch (MyProperty) 
      { 
       case 1: 
        MyView.Sort = "Field1 ASC"; 
        break; 
       case 2: 
        MyView.Sort = "Field2 ASC"; 
        break; 
       default: 
        MyView.Sort = "Field3 ASC"; 
        break; 
      } 
15

Lubię odpowiedź BFree, choć będę martwić się o ryzyko, że mój kod będzie skończyć aktualizację sklonowanego tabeli zamiast prawdziwej. (Nie myślałem przez niego na tyle, aby wiedzieć, czy to jest rzeczywiście problem, jeśli jesteś tylko stosując metodę rozszerzenia w DataView.)

Można to zrobić na oryginalnym DataTable dodając obliczoną DataColumn do niego (za pomocą właściwości Expression), a następnie sortowanie jej wartości.

W twoim przypadku będzie to coś jak:

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

który sortuje SomeValue pierwszy, drugi i AnotherValue wszystkiego innego po tym.

+0

Witam, potrzebuję tego rodzaju rozwiązania. Więc wszystko, co muszę zrobić, to używać tylko tych linii kodu? Popraw mnie, jeśli się mylę. Co się stanie, jeśli będzie więcej niż 2 kolumny, które chcę posortować? Na przykład kolumna ma te wartości w wierszu "A", "B", "C", "D". Chcę, aby zamówienie było B, A, D, C. Jak zrobić to za pomocą aplikacji? przepraszam, jestem trochę nowa z .net. Używanie VB na tym jednym – Wax

+0

+1 Jest to idealne rozwiązanie, gdy klonowanie datatable nie jest opcją, ani żadna podobna technika jak zastępowanie innego widoku danych. Niemal wszystkie inne rozwiązania, które znalazłem rozproszone w StackOverflow i reszcie Internetu, wiążą się z pewnym powieleniem oryginalnych danych, które mogą być kosztowne w przypadku dużych tabel i mogą prowadzić do problemów z synchronizacją przy wstawianiu/aktualizowaniu/usuwaniu itp. Chciałbym móc to zrobić 10 razy. ;) – SQLServerSteve

4

Wiem, że ten post jest nieco starszy, ale poszedłem o tym nieco inaczej, wdrażając IComparable. W tym przykładzie chciałem sortować według wersji (która jest w formacie 0.0.0.0 jako ciąg).

Oto klasa Versioning który implementuje 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)); 
    } 
} 

a kiedy dodać kolumnę do tabeli, zamiast dodawania wersji jako ciąg znaków, należy dodać ją jako klasa Versioning:

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

następnie rodzaju zwykle:

_view.Sort = "Version"; 
Powiązane problemy