2017-05-29 2 views
0

Ich versuche, die Ausgabe einer Anwendung zu optimieren, die ich vor einiger Zeit schrieb und obwohl ich in vielen Fronten viel erreicht habe, kämpfe ich um die Funktion zu beschleunigen, die die Ergebnisse exportieren einer Listview zu einer .xlsx-Datei.Export ListView nach Excel - Kämpfen mit schmerzhafter Leistung

Ich bin Interop verwenden, es zu tun, wie unten dargestellt:

Imports Excel = Microsoft.Office.Interop.Excel 
Imports System 
Imports System.IO 
Imports System.Data.OleDb 
Imports System.Threading 
Imports System.Linq 
Imports System.Data.SqlClient 

Und dies ist die Funktion, die die Daten in der Listenansicht exportiert:

Private Function ExportListViewTab5ToXLSxFile(ByRef FileNameWithoutExtension As String, ByRef OutputDir As String) As Boolean 

     Try 
      Dim objExcel As Excel.Application = New Excel.Application 
      Dim bkWorkBook As Excel.Workbook 
      Dim shWorkSheet As Excel.Worksheet 
      Dim i As Integer 
      Dim j As Integer 

      objExcel = New Excel.Application 
      bkWorkBook = objExcel.Workbooks.Add 
      shWorkSheet = CType(bkWorkBook.ActiveSheet, Excel.Worksheet) 

      For i = 0 To lvObjectsTab5.Columns.Count - 1 
       shWorkSheet.Cells(1, i + 1) = lvObjectsTab5.Columns(i).Text 
      Next 
      For i = 0 To lvObjectsTab5.Items.Count - 1 
       For j = 0 To lvObjectsTab5.Items(i).SubItems.Count - 1 
        shWorkSheet.Cells(i + 2, j + 1) = lvObjectsTab5.Items(i).SubItems(j).Text 
       Next 
      Next 

      shWorkSheet.Columns.AutoFit() 

      Try 

       '///////////////// 
       '// Save report // 
       '///////////////// 
       Try 
        shWorkSheet.SaveAs(OutputDir & "\" & FileNameWithoutExtension & ".xlsx") 
       Catch ex As Exception 
        MessageBox.Show("A exportação do relatório foi cancelada pelo usuário!", "Exportação cancelada!", MessageBoxButtons.OK, MessageBoxIcon.Error) 
        Return False 
       End Try 

       '/////////////////////////////////// 
       '// Close EXCEL.EXE COM processes // 
       '/////////////////////////////////// 

       bkWorkBook.Close() 
       objExcel.Workbooks.Close() 
       NAR(bkWorkBook) 
       objExcel.Quit() 
       NAR(objExcel) 

       '////////////////////////// 
       '// Open report in Excel // 
       '////////////////////////// 

       Process.Start(OutputDir & "\" & FileNameWithoutExtension & ".xlsx") 
       Return True 

      Catch ex As Exception 
       MessageBox.Show("Falha ao exportar o arquivo '" & FileNameWithoutExtension & ".xlsx' para '" & OutputDir & "'", "Falha ao exportar relatório!" & vbCrLf & vbCrLf & _ 
           "Detalhes do erro:" & vbCrLf & vbCrLf & _ 
           ex.ToString, MessageBoxButtons.OK, MessageBoxIcon.Error) 
       Return False 
      End Try 
     Catch ex As Exception 
      MessageBox.Show("Falha ao exportar o arquivo '" & FileNameWithoutExtension & ".xlsx' para '" & OutputDir & "'", "Falha ao exportar relatório!" & vbCrLf & vbCrLf & _ 
          "Detalhes do erro:" & vbCrLf & vbCrLf & _ 
          ex.ToString, MessageBoxButtons.OK, MessageBoxIcon.Error) 
      Return False 
     End Try 

    End Function 

Die Listenansicht enthält 10 Spalten und Es dauert 4 Minuten, um 2000 Zeilen zu exportieren. Es ist zu viel. Ich habe stundenlang gegoogelt und nach mehreren Beispielen für Performance-Probleme gesucht, aber alle Beispiele, die ich gefunden habe, waren ähnlich wie meine.

Kann mir jemand sagen, wie ich die Leistung meiner Funktion mit .NET-Code verbessern könnte? In einem typischen Szenario enthält diese Listenansicht 15.000 Zeilen. Ich beschränke mich auf 2000, also ist es weniger schmerzhaft für die Benutzer.

Irgendwelche Vorschläge?

Vielen Dank im Voraus, Daniel

+0

Ein häufiges Problem. Schreiben Sie den gesamten Text aus der Listenansicht während der Doppelschleife in ein 2D-Array. Dann schreibe das Array auf einmal in das Arbeitsblatt! NICHT mit einer Schleife. Wie 'shWorkSheet.Cells (2, 1) .Resize (numberOfRows, numberOfColumns) .Value = arrayFilledByDoubleLoop' Dies schreibt A2 als obere linke Ecke der Ausgabedaten. – MacroMarc

+1

Sie könnten stattdessen auch das 'ClosedXml' NuGet-Paket ausprobieren von Interop. In meiner App erstelle ich eine Tabelle mit 85.000 Zeilen, 18 Spalten in 15 Sekunden. – Phil

Antwort

1

Versuchen Sie, alle Werte als Bereich auf einmal anzuwenden. So etwas könnte es tun.

dim Values(lvObjectsTab5.Items.Count, lvObjectsTab5.Items(i).SubItems.Count) as object 
dim Range as Excel.Range = shWorkSheet.Range("A1","J" & (lvObjectsTab5.Items.Count+ 1)) 

For i = 0 To lvObjectsTab5.Columns.Count - 1 
    Values(0, i) = lvObjectsTab5.Columns(i).Text 
Next 

For i = 0 To lvObjectsTab5.Items.Count - 1 
     For j = 0 To lvObjectsTab5.Items(i).SubItems.Count - 1 
      Values(i+1,j) = lvObjectsTab5.Items(i).SubItems(j).Text 
     Next 
Next 
Range.value = Values 

EDIT: die Spaltenüberschriften auf die Werte-Matrix einzufügen.

+1

Jesus ... Die Antwort von @AugustoQ hat es nur von 12 Minuten auf 30 Sekunden reduziert ... Ich denke, dieser Thread wird einer Gruppe von Leuten mit dem gleichen Problem helfen ... Danke! –

+0

Der einzige Nebeneffekt dieser Lösung ist, dass der Header mit den Spaltennamen aus der Listenansicht nicht mehr exportiert wird. –

+0

Sie können die Header auch exportieren, ich habe vergessen, es auf meinen Code zu setzen, aber wenn Sie die erste Zeile der 'Values ​​(,)' Matrix als Header-Namen platzieren, wird es auch die Header-Namen haben – AugustoQ