DataView.Sort: molto più di asc / desc (è necessario un ordinamento personalizzato)

Ho creato un report da un set di dati. Il set di dati utilizza la proprietà Ordina per ordinare i dati. So che posso creare un’espressione di ordinamento come questa:

“campo desc, campo2 asc”

Ma quello di cui ho bisogno ora è un modo per fare un ordinamento personalizzato. In SQL, posso eseguire un ordinamento personalizzato facendo qualcosa del genere:

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

Per ridefinire sostanzialmente il mio tipo (cioè, qualche valore viene prima di un altro valore).

È ansible fare qualcosa di simile come un’espressione di ordinamento contro un DataView?

Ok, l’ho appena montato molto velocemente, e non ho fatto tutto il necessario controllo degli errori e il controllo nullo, ma dovrebbe darti un’idea e dovrebbe essere sufficiente per iniziare:

 public static class DataTableExtensions { public static DataView ApplySort(this DataTable table, Comparison comparison) { DataTable clone = table.Clone(); List rows = new List(); 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; } } 

Uso:

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

// Ordina per StringValue:

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

Risultato:

11 Undici

14 Quattordici

10 Dieci

13 Tredici

12 Dodici

// Ordina per IntValue:

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

Risultato:

10 Dieci

11 Undici

13 Tredici

12 Dodici

14 Quattordici

EDIT: modificato al metodo di estensione.

Ora nel tuo Lambda (o puoi creare un metodo di confronto completo) puoi fare qualsiasi tipo di logica di ordinamento personalizzata di cui hai bisogno. Ricorda, -1 è minore di, 0 è uguale a, e 1 è maggiore di.

Mi piace la risposta di BFree, anche se mi preoccuperei del rischio che il mio codice finisse per aggiornare la tabella clonata piuttosto che quella reale. (Non ci ho pensato abbastanza per sapere se questo è effettivamente un problema se stai usando il metodo di estensione solo in un DataView .)

È ansible eseguire questa operazione sul DataTable originale aggiungendo una DataColumn calcasting su di esso (utilizzando la proprietà Expression ) e quindi ordinando il relativo valore.

Nel tuo caso sarebbe qualcosa di simile:

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

che ordina prima SomeValue , AnotherValue second e tutto il resto.

So che questo post è un po ‘più vecchio, ma sono andato su questo leggermente diverso implementando IComparable. In questo esempio, ho voluto ordinare per versione (che è nel formato 0.0.0.0 come stringa).

Ecco la class Versioning che implementa 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)); } } 

E quando aggiungi la colonna alla tabella, invece di aggiungere Version come stringa, la aggiungi come class Versioning:

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

E poi ordina normalmente:

 _view.Sort = "Version"; 

Io non la penso così È tuttavia ansible modificare l’SQL per restituire una colonna “CustomSort” che è il risultato dell’istruzione case:

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

È ansible utilizzare un’istruzione if o a switch per ottenere funzionalità simili all’istruzione case select:

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

O

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