Abou Chleih

{the magic lies between the brackets}

Menü Schließen

Monat: August 2013

[C#] Sortieren einer DataTable-Spalte nach einer Spalte eines anderen DataTable

Ich hatte die Aufgabe eine Spalte einer DataTable bzw. die DataTable(1) an sich nach der Spalte einer anderen DataTable(2) zu sortieren ohne die Reihenfolge der zweiten DataTable(2) zu verändern.
Um zu verdeutlichen, wie die Aufgabenstellung genau aussah, habe ich hier Screenshots der DataTables visualisiert in einem DataGridView im Ist/Soll-Zustand:

Die Sort-Methode des DataGridView, ebenso wie die Sort-Eigenschaft eines DataViews,

DataTable.DefaultView.Sort = "Spaltenname ASC"

bieten nur die Möglichkeit eine Spalte auf(Ascending)- bzw. absteigend(Descending) zu sortieren.

So musste ich mir dann einen eigenen Weg finden, die Aufgabe zu lösen. Die Lösung möchte ich euch natürlich nicht vorenthalten.

 private void sortList(string pExcelDataColumnName, string pSortByListColumnName)
        {
            excelDataTable.Columns.Add("TempOrderColumn", typeof(Int32)); //Dient später zum Sortieren der Zeilen

            foreach (DataRow row in excelDataTable.Rows)
            {
                foreach (DataColumn column in excelDataTable.Columns)
                {
                    if (column.ColumnName == pExcelDataColumnName)
                    {
                        object tempRowIndex = GetRowIndexOfCellValue(row[column], pSortByListColumnName);
                        row["TempOrderColumn"] = tempRowIndex;
                    }
                }
            }

            DataView dv = excelDataTable.DefaultView;
            dv.Sort = "TempOrderColumn ASC";
            excelDataTable = dv.ToTable();
            excelData_dataGridView.Refresh();
        }

In dieser Methode erstellen wir erstmal eine weitere Spalte, welche uns später zum Sortieren dient, danach durchlaufen wir alle Zellen der unsortierten Liste(zweimal foreach) und fragen ab, ob sich einer der Zellen in der zuvor definierten Spalte befindet(Parameter der Methode).
Sollte dies der Fall sein, so rufen wir folgende Methode auf und übergeben den Inhalt der aktuellen Zelle, sowie den Namen der zu vergleichenden Spalte:

private object GetRowIndexOfCellValue(object pCellValue, string pSortByListColumnName)
        {
            foreach (DataRow row in sortByDataTable.Rows)
            {
                foreach (DataColumn column in sortByDataTable.Columns)
                {
                    if (column.ColumnName == pSortByListColumnName && pCellValue.Equals(row[column]))
                    {
                        return sortByDataTable.Rows.IndexOf(row);
                    }
                }
            }
            return -1;
        }

Diese Methode durchläuft sämtliche Zellen der Liste, nach welcher wir sortieren wollen und prüft ob sich die Zelle in der als Parameter übergeben Spalte befindet(indem sie den übergeben Spaltennamen mit jenem der aktuellen Spalte(Column) vergleicht) und ob der Inhalt der Zelle mit jenem Inhalt übereinstimmt, welcher als Parameter übergeben wurde.

Sollte beide Abfragen ‚wahr‘ sein, so geben wir den Index der aktuellen Zeile zurück. Dafür verwenden wir die folgende Methode

return sortByDataTable.Rows.IndexOf(row);

Der Rückgabewert wird dann mittels

row["TempOrderColumn"] = tempRowIndex;

in die temporäre Spalte geschrieben und zu guter Letzt mit folgendem Code sortiert:

            DataView dv = excelDataTable.DefaultView;
            dv.Sort = "TempOrderColumn ASC";
            excelDataTable = dv.ToTable();
            excelData_dataGridView.Refresh();

Dies ist nötig, da man einer DataTable nicht direkt sortieren kann und somit den Umweg über das Erstellen eines DataViews gehen muss, diesen dann mittels

dv.Sort = "Spaltenname ASC" //ASC steht für 'ascending' aufsteigend
//DESC steht für 'descending' absteigend

sortiert und das DataView dann wieder in die DataTable wandelt.

Das Ergebnis sieht wie folgt aus:
2013-08-23 15_51_20-Excel nach Liste sortieren

Nun muss ich nur noch eine Excel-Tabelle aus der DataTable bzw dem DataGridView erstellen. Wie man dies bewerkstelligt, zeige ich in meinem nächsten Blogeintrag

[C#] Auslesen einer Excel Datei #2 – OleDB

Teil 1: [C#] Auslesen einer Excel Datei #1 – Interop-Assembly

OleDB steht für Object Linking and Embedding, Database und bietet einem im Gegensatz zu Interop-Assembly die Möglichkeit auf verschiedenste Datenquellen (bspw. auch auf Datenbanken zuzugreifen). Zugleich muss im Gegensatz zu Interop-Assembly kein Microsoft Excel installiert sein und die meisten Controls, wie z.B. DataGridView, akzeptieren out-of-the-box die Datenquelle (Data Source) welche OleDB bietet.

Hier ein Zitat aus dem MSDN:

OLE DB is a set of COM-based interfaces that expose data from a variety of sources. OLE DB interfaces provide applications with uniform access to data stored in diverse information sources, or data stores. These interfaces support the amount of DBMS functionality appropriate to the data store, enabling the data store to share its data.

OleDB hat einige Vorteile gegenüber Interop-Assembly:

  • Microsoft Excel muss nicht installiert sein
  • Es ist um einiger schneller als Interop

Natürlich aber auch Nachteile

  • OleDB bietet im Vergleich zu Interop in Bezug auf Excel weniger Möglichkeiten, vor allem bezüglich Zelleninformationen, wie Farbe, Rahmen oder Formatierung

Nun aber zur Nutzung von OleDB

Normalerweise bindet Visual Studio automatisch System.Data-Assembly ein und wir müssen nur noch den Namespace mittels

using System.Data.OleDb;

einbinden

Sollte es dennoch zu folgender Fehlermeldung

Fehler 1

Der Typ- oder Namespacename „OleDb“ ist im Namespace „System.Data“ nicht vorhanden. (Fehlt ein Assemblyverweis?)

müssen wir einen Assemblyverweis erstellen.

Dazu einfach mit der rechten Maustaste auf „Verweise“ klicken:

20130811_OleDBTest - Microsoft Visual Studio_000033

„Verweis hinzufügen“ wählen und in den Framework-Assemblys nach System-Data suchen und diese Assembly dann wählen.20130811_Verweis-Manager - OleDBTest_000034

Zu guter Letzt noch mit „OK“ bestätigen.

Ich persönlich bevorzuge es Objekten mittels using eine definierte Gültigkeit zuzuweisen, dies bedeutet, dass das in der Using-Anweisung definierte Objekt nach dem Verlassen der Anweisung nicht mehr benötigt wird und zerstört werden kann.

Dadurch ist es aber nötig den ConnectionString, vor dem Erstellen der OleDbConnection zu definieren und per Paramter zu übergeben.
Um einen ConnectionString zu erstellen, verwende ich den OleDbConnectionStringBuilder:

Dieser bietet eine einfache Möglichkeit, den Inhalt von Verbindungszeichenfolgen zu erstellen und zu verwalten, die von der OleDbConnection-Klasse verwendet werden.


OleDbConnectionStringBuilder csbuilder = new OleDbConnectionStringBuilder();
 csbuilder.Provider = "Microsoft.ACE.OLEDB.12.0";
 csbuilder.DataSource = "Pfad zu Excel-Datei";
 csbuilder.Add("Extended Properties", "Excel 12.0 Xml;HDR=YES");

Der Provider ist eine Softwarebibliothek, welche die nötigen Werkzeuge bietet, um auf eine Datenquelle zuzugreifen. Im ConnectionString werden die Informationen, welche den Provider in die Lage versetzen auf die Quelle zuzugreifen, hinterlegt.
Für ConnectionStrings empfehle ich: http://www.connectionstrings.com/

Im Property DataSource wird der Pfad zu Excel-Datei angegeben.

Mittels der Methode Add werden die Informationen hinterlegt, welche den Typ der Datei und Informationen zum Inhalt definieren.
In diesem Beispiel wird hinterlegt, dass es sich um eine Excel-Datei handelt, welche mit Excel 2010 erstellt wurde(Excel 12.0) und deren erste Zeile Überschriften(Header/HDR) sind.

Da nun die wichtigsten Eigenschaften definiert wurden, können wir das erste Tabellenblatt der Excel-Datei auslesen.
Dazu verwenden wir die SQL-Abfrage

SELECT * FROM [“ + Name_des_Tabellenblattes + „]

(Die eckigen Klammern werden zwingend benötigt)

             using (OleDbConnection connection = new OleDbConnection(csbuilder.ConnectionString))
            {
                DataTable sheet1 = new DataTable();
                connection.Open();
                string sqlQuery = @"SELECT * FROM [" + Name_des_Tabellenblattes + "]";
                using (OleDbDataAdapter adapter = new OleDbDataAdapter(sqlQuery, connection))
                {
                    adapter.Fill(sheet1);
                    excelData_dataGridView.DataSource = sheet1;
                }
                connection.Close();
            }

Und erstellen ein Objekt vom Typ OleDbDataAdapter mit den Parametern „SQL-Query“ und dem ConnectionString.
Danach füllen wir den DataTable mittels adapter.Fill(Name_des_DataTables) und füllen ein DataGridView mittels

DataGridView.DataSource = Name_des_DataTables;

Namen der Tabellenblätter auslesen

Nun ist natürlich ungeschickt den Namen des Tabellenblattes hartcodiert im Code zu hinterlegen.
Um die Tabellenblattnamen auszulesen und in ein StringArray zu laden verwenden wir folgenden Code:

OleDbConnectionStringBuilder csbuilder = new OleDbConnectionStringBuilder();
csbuilder.Provider = "Microsoft.ACE.OLEDB.12.0";
csbuilder.DataSource = pExcelPath;
csbuilder.Add("Extended Properties", "Excel 12.0 Xml;HDR=YES");

System.Data.DataTable dt = null;

using (OleDbConnection connection = new OleDbConnection(csbuilder.ConnectionString))
{
    connection.Open();
    dt = connection.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, null);
    connection.Close();
}

String[] excelSheets = new String[dt.Rows.Count];

int i = 0;
foreach (DataRow row in dt.Rows)
{
    excelSheets[i] = row["TABLE_NAME"].ToString();
    i++;
}

Mit dem StringArray kann man nun eine ganze Menge anfangen.
Ich habe beispielsweise das StringArray als Parameter an ein Objekt einer Form übergeben, welches jeden String im Array(mittels foreach-Schleife) in eine ListView kopiert und man so das gewünschte Tabellenblatt auswählen kann.

DemoProjekt

Hier könnt ihr das Demoprojekt herunterladen:

20130811_Verweis-Manager - OleDBTest_000034

OleDBTest

Gabelausbau/-tausch bei der SV 650 S

Durch einen Unfall wurden bei der SV 650 S (Kante) die Standrohre verbogen, andere Schäden an der Gabel, wie verzogene Brücken ließen sich nicht ausschließen, deshalb besorgten wir uns eine neue Gabel, welche dann eingebaut werden musste.
Bevor man anfangen kann, sollte man die Verkleidung der SV abnehmen, d.h. Kanzel + Geweih entfernen.
Ich gehe hierauf nicht genauer ein, da es bei näherem Hinschauen selbsterklärend sein sollte.

Nun kann man die SV aufbocken. Wir hatten keinen Frontheber zur Verfügung, deshalb „bastelten“ wir uns eine eigene Lösung.
Mit Hilfe einer Leiter und eines Spanngurtes zogen wir die SV am Rahmen in die Luft. Diese Methode hatte sich schon beim Ausbau der Schwinge bewährt.

Nun beginnen wir:
Als erstes muss man mit Hilfe eines 12er Innensechskant (Inbus) das Vorderrad ausbauen, dazu die Sicherungsschraube lösen und die Vorderradachse mit Hilfe des 12er Inbus ausbauen.
Vorderradachse_ausbau
Sobald man die Achse entfernt hat, kann man das Rad nach vorne heraus ziehen.

Aufpassen!
Der, auf der in Fahrtrichtung linken Seite platzierte, Geschwindigkeitssensor darf nicht beschädigt werden!

Nun, da das Vorderrad ausgebaut ist, kann man den Frontfender und die Bremsanlage ab- bzw. ausbauen.

Ab sofort die vordere Bremse nicht mehr betätigen!

Um ersteren zu lösen, muss man die äußeren Verkleidungsschrauben mit einem Inbus und die, an der Innenseite angebrachten, Sechskantschrauben mit einem 10er Schlüssel entfernen.
Den Frontfender kann man dann auch einfach nach vorne herausziehen (auch hier etwas vorsichtig mit dem „Plastik“ umgehen).
Die Bremssättel löst man einfach, indem man die Halteschrauben mit einem 14er Außensechskant entfernt.
Die restlichen Halterung, also die der Bremsleitungen, des Geschwindigkeitssensor, … lösen.
Aufpassen, dass die Bremsssättel nicht einfach lose herumhängen und zu viel Zug auf den Leitungen liegt. Ich habe die Bremssättel einfach mit einem Kabelbinder an der Leiter festgebunden.

Nun liegen die Standrohre und Tauchrohre frei.
Die beiden kann man einfach nach unten raus ziehen, wenn man die folgenden Schrauben löst:
Standrohr_ausbau

Bei den Schrauben der Gabelbrücken handelt es sich, wenn ich mich richtig erinnere, um 14er Außensechskantschrauen, beim Stummel eventuell um einen 12er Außensechskant.

Nun entfernen wir die Steuerkopfmutter der oberen Gabelbrücke und entfernen diesezusammen mit der Unterlagscheibe (oder in Hochdeutsch: Unterlegscheibe).

Gabelbrücke_oben

Anschließend kann man die obere Gabelbrücke ganz einfach nach oben abziehen.
Im Anschluss entfernen wir die beiden Halterungsschrauben für die untere Gabelbrücke, dazu nehmen wir das gezeigte Spezialwerkzeug (im Boardwerkzeug).
Und lösen die obere Schraube, entfernen diese und die Zwischenlagscheibe, danach entfernen die Sicherungsschraube.
Jetzt lösen wir die Konterschraube und schrauben diese raus.
Eine zweite Person sollte gleichzeitig die untere Gabelbrücke mitsamt Lenkkopf halten, sodass diese nicht nach unten herausrutschen.
Gabelbrücke_oben_2

Nun hat man die Gabel ausgebaut und kann die neue einbauen, die Lager der alten können eventuell wiederverwendet werden.
Ein bisschen Fett auf die Lager und wieder aufschieben, aber die Lager nicht einfach fallen lassen!

Fertig.
Einbau erfolgt in umgekehrter Reihenfolge.

Anzugsmomente:
Vorderer Bremszylinder 39 Nm
Spannschrauben der Standrohre 23 Nm
Steuerkopfmutter 90 Nm
Vorderachse 65 Nm
Vorderachsen-Klemmschraube 23 Nm

© 2018 Abou Chleih. Alle Rechte vorbehalten.

Thema von Anders Norén.