2016-06-24 18 views
0

Ich habe Code wie unten (ich habe es generifiziert und reduziert, um nur das Problem zur Verfügung zu stellen). Der Code funktioniert, das heißt, er nimmt eine DataGridView.DataSource und ulitmatly, EPPlus, die Daten in eine Excel-Datei ausgibt. Meine Frage bezieht sich auf Kovarianz und wie man sie benutzt, denke ich.DataGridView mit Kovarianz?

Sie sehen also, es baut newList basierend auf dem Typ, den es in der DataSource gefunden hat. Dann fügen Sie die Daten mit den Eigenschaften someClassObject.Name, .Address and .Phone, die für diesen Typ eindeutig sind, etwas weiter unten hinzu.

Mein Problem ist, dass es etwa 75 verschiedene Klassen gibt, die über den Parameter DataGridView übergeben werden könnten. Jede Klasse hat ihre eigenen einzigartigen Eigenschaften (d. H. Nicht notwendigerweise Name, Adresse, Telefon), obwohl alle Objekte in gegebenen DataGridView.DataSource derselben Klasse angehören.

Ich könnte eine Riese Switch-Anweisung basierend auf type.FullName haben und dann jeder würde seine eigene for-Schleife haben, um die Eigenschaft Werte der Zelle zuzuweisen. Das würde funktionieren, wäre aber unglaublich umständlich. Gibt es einen besseren Weg, dies zu tun?

public void openExcelReport(ref DataGridView dataGridView, bool bolSave = false, bool bolOpen = true, string pageTitle = "EXPORTED DATA") 
{ 
    // put dataGridView.DataSource into a List 
    object firstItem = null; 
    var myDataSource = dataGridView.DataSource; 
    var myList = ((System.Windows.Forms.BindingSource)dataGridView.DataSource).List; 
    firstItem = ((System.Collections.IList)myList)[0]; 
    var type = firstItem.GetType(); 

    Type PROJECT1_TYPE = typeof(Project1.SomeClass); 
    Type PROJECT2_TYPE = typeof(Project2.SomeOtherClass); // many more of these 

    dynamic newList = null; 

    if (type.FullName.Equals(PROJECT1_TYPE.FullName)) 
    { 
     newList = new List<Project1.SomeClass>(); 
     foreach (Project1.SomeClass someClassObject in myList) 
     { 
      newList.Add(someClassObject); 
     } 
    } 

    ExcelPackage package = new ExcelPackage(); 
    using ((package)) // use EPPlus 
    { 
     // Create the worksheet 
     ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Worksheet 1"); 

     // Load the datatable into the sheet, starting from cell A1. Print the column names on row 1 

     System.Data.DataTable dataTable = new System.Data.DataTable(); 

     dataTable.Columns.Add("Id"); 
     dataTable.Columns.Add("FirstColumn", typeof(string)); 
     dataTable.Columns.Add("SecondColumn", typeof(string)); 
     dataTable.Columns.Add("ThirdColumn", typeof(string)); 

     dataTable.Columns[0].AutoIncrement = true; 

     var column_id = 0; 
     foreach (Project1.SomeClass someClassObject in "FirstColumn") 
     { 
      DataRow dataRow = dataTable.NewRow(); 

      dataRow["FirstColumn"] = someClassObject.Name; 
      dataRow["SecondColumn"] = someClassObject.Address; 
      dataRow["ThirdColumn"] = someClassObject.Phone 

      dataTable.Rows.Add(dataRow); 

      column_id += 1; 

     } 

     // worksheet is now populated, so save Excel File  
     ... 

} 
+1

Für die Klassen, die Sie übergeben, könnten Sie diese ändern, um eine Schnittstelle zu implementieren, die eine 'GetDataRow()' (oder etwas ähnliches) Funktion hat, so dass Sie diesen Code dann in der Klassenimplementierung selbst haben können Hier tun Sie einfach 'dataTable.Rows.Add (someClassObject.GetDataRow())'. Und sei damit fertig. Dies würde Sie davon abhalten, einen "switch" - oder "if/else" -Block zu benötigen, da die Einzelheiten zum Erzeugen des 'DataRow' direkt mit der Klasse verbunden sind, die die gewünschten Spalten als Eigenschaften enthält. – gmiley

Antwort

2

Statt in dieser Funktion die DataRow Schöpfung zu tun, man könnte es zu den Klassenimplementierungen bewegen, um eine gemeinsame Schnittstelle verwenden, es zu erzwingen, zum Beispiel:

public interface DataRowConvertable 
{ 
    DataRow GetDataRow(); 
} 

public class SomeClass : DataRowConvertable 
{ 
    public SomeClass() { } 
    public SomeClass(string name, string address, string phone) 
    { 
     Name = name; 
     Address = address; 
     Phone = phone; 
    } 

    public string Name { get; set; } 
    public string Address { get; set; } 
    public string Phone { get; set; } 

    public DataRow GetDataRow() 
    { 
     DataRow row = GetDataTable().NewRow(); 
     row["Name"] = this.Name; 
     row["Address"] = this.Address; 
     row["Phone"] = this.Phone; 
     return row; 
    } 

    public static DataTable GetDataTable() 
    { 
     DataTable table = new DataTable("SomeClassTable"); 
     table.Columns.Add("Name", typeof(string)); 
     table.Columns.Add("Address", typeof(string)); 
     table.Columns.Add("Phone", typeof(string)); 
     return table; 
    } 
} 

Sie es weiter gehen könnten, aber das sollte dir eine gute Alternative und einen Platz zum Starten geben. Sie können die GetDataTable-Funktion entweder public lassen und diese auch verwenden, um Ihre Tabelleninstanz zu erstellen oder sie als privat zu definieren und nur intern zu verwenden. Ich würde mich für Ersteres entscheiden und das in Ihrer Funktion verwenden, um die Tabelle vor dem Füllen zu initialisieren. Sie könnten sogar den Modifizierer static loswerden und ihn zu Ihrer Schnittstelle hinzufügen, aber ich bevorzuge die statische Verwendung in dieser Instanz, da er nicht auf die Instanz der Klasse und die beteiligten Daten angewiesen ist, sondern nur auf die Struktur.

So oder so, können Sie dann den Code, den Sie haben oben ändern wie folgt aussehen:

ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Worksheet 1"); 
System.Data.DataTable dataTable = Project1.SomeClass.GetDataTable(); 

foreach (Project1.SomeClass someClassObject in myList) 
{ 
    dataTable.Rows.Add(someClassObject.GetDataRow()); 
} 

Wenn Sie eine erhöhte id Spalte benötigen, könnte man leicht hinzufügen, dass in den GetDataTable/GetDataRow Funktionen und aktualisiert sie genau wie du oben warst.

Dies ist nur ein kurzes Beispiel, es könnte sehr wahrscheinlich einige bereinigt und optimiert werden, aber es vermittelt immer noch die Idee. Hoffe, es hilft dir aus.

+0

Danke. Ich war so konzentriert auf "Kovarianz", dass ich nichts anderes dachte. Ich werde versuchen, dies umzusetzen und zu dir zurück zu kommen. –