Question

I've got code that manually copies data from two datatables into two excel worksheets and then does a comparison on the data in the two datatables.

I've got the performance of inserting data into excel much better, but I think I have a bottle neck where I select rows that are missing in and highlight them as red, and select cells that are different and highlight them in yellow.

I am wondering about the calls where I find a range and call .Select() and then set Selection.Style.

I am already doing: oldInstance.Application.ScreenUpdating = false;

Just wondering if there are any other suggestions for increasing performance?

In the code below there is lots of looping etc, but the main performance hit seems to be actually applying the formatting in excel ( if I comment out the code that does the .Select and sets Selection.Style it is much faster ).

  IEnumerable<DataRow> oldOnly = oldTable.Rows.OfType<DataRow>().Except( newTable.Rows.OfType<DataRow>(), lambdaComparer );
  int oldOnlyRows = 0;
  foreach ( var dataRow in oldOnly )
  {
     int excelRowIndex = dataRow[ addedRowIndexColumnName ].ToString().ParseInt() + 2;
     // Logger.Info( "Row: {0} Old Only: {0}",excelRowIndex , dataRow[ keyColumnName ] );
     ( oldInstance.ActiveSheet.Rows[ excelRowIndex ] as Range ).Select();
     oldInstance.Selection.Style = "Bad";
     oldOnlyRows++;
  }


  int newOnlyRows = 0;
  IEnumerable<DataRow> newOnly = newTable.Rows.OfType<DataRow>().Except( oldTable.Rows.OfType<DataRow>(), lambdaComparer );
  foreach ( var dataRow in newOnly )
  {
     int excelRowIndex = dataRow[ addedRowIndexColumnName ].ToString().ParseInt() + 2;
     // Logger.Info( "Row: {0} New Only: {0}", excelRowIndex, dataRow[ keyColumnName ] );
     ( newInstance.ActiveSheet.Rows[ excelRowIndex ] as Range ).Select();
     newInstance.Selection.Style = "Bad";
     newOnlyRows++;
  }

  int differentCells = 0;
  var enumerable = ( ( from o in oldTable.Rows.OfType<DataRow>() join n in newTable.Rows.OfType<DataRow>() on o[ keyColumnName ] equals n[ keyColumnName ] select new { o, n } ) );
  foreach ( var x1 in enumerable )
  {
     for ( int i = 0; i < newTable.Columns.Count -1; i++ ) // use Count - 1 so we ignore the last "RowIndex" column
     {
        if ( x1.o[ i ].ToString() != x1.n[ i ].ToString() )
        {
           int oldExcelRowIndex = x1.o[ addedRowIndexColumnName ].ToString().ParseInt() + 2;
           var oldRange = oldInstance.GetCell( oldExcelRowIndex, i + 1 );
           oldRange.Select();
           oldInstance.Selection.Style = "Neutral";

           int newExcelRowIndex = x1.n[ addedRowIndexColumnName ].ToString().ParseInt() + 2;
           var newRange = newInstance.GetCell( newExcelRowIndex, i + 1 );
           newRange.Select();
           newInstance.Selection.Style = "Neutral";
           differentCells ++;
        }
     }
  }
Was it helpful?

Solution

The trick is to avoid calls to Select.

For example:

 ( oldInstance.ActiveSheet.Rows[ excelRowIndex ] as Range ).Select();
 oldInstance.Selection.Style = "Bad";

Should be:

 ( oldInstance.ActiveSheet.Rows[ excelRowIndex ] as Range ).Style = "Bad";

This takes my formatting code from 41 seconds down to 9 seconds.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top