PC Review


Reply
Thread Tools Rate Thread

C#/Excel Code Slow; Suggestions?

 
 
=?Utf-8?B?Sm9uT2ZBbGxUcmFkZXM=?=
Guest
Posts: n/a
 
      14th Jul 2007
Good evening, everyone. I have a simple C# program that copies a lot of data
into Excel, with some minimal formatting, and it runs VERY slowly. Once I
have the data (in DataGridView controls), I can write CSV files in seconds,
but the Excel part takes hours. This is the main code, sorry it's not very
readable in this forum:

int r, c;

....

r = 0;
foreach (DataGridViewRow row in grid.Rows)
{
for (c = 0; c < numColumns; /*iterated at bottom of block*/)
{
object value = row.Cells[c].Value;

if (value != null)
{
file.Write(Program.CleanForCSV(value.ToString()));
worksheet.Cells[r+3, c+1] = value; // Skip ahead to row #3, to allow
space for headers
}

if (++c < numColumns) file.Write(','); // We don't want a comma after
the last column
}
if (++r < numRows) file.WriteLine();
}

The odd iteration is the simplest way I could think of to efficiently avoid
trailing commas in CSV.
I've done some simple profiling at the procedure level, and there's no
single part of the export process that takes much longer than the rest. Can
I copy data by row or even copy the content of the whole DataGridView? It
seems like that should be possible, but I haven't seen where. Any ideas?
Thanks!
 
Reply With Quote
 
 
 
 
Tim
Guest
Posts: n/a
 
      14th Jul 2007
Since you're communicating between processes, a cell-by-cell transfer of a
lot of data is going to be slow, since each call has significant overhead
and you're making one call per cell value. Try building an array and
filling the sheet in one step.

Tim


"JonOfAllTrades" <(E-Mail Removed)> wrote in message
news:7E84EA74-3752-4E4E-8024-(E-Mail Removed)...
> Good evening, everyone. I have a simple C# program that copies a lot of
> data
> into Excel, with some minimal formatting, and it runs VERY slowly. Once I
> have the data (in DataGridView controls), I can write CSV files in
> seconds,
> but the Excel part takes hours. This is the main code, sorry it's not
> very
> readable in this forum:
>
> int r, c;
>
> ...
>
> r = 0;
> foreach (DataGridViewRow row in grid.Rows)
> {
> for (c = 0; c < numColumns; /*iterated at bottom of block*/)
> {
> object value = row.Cells[c].Value;
>
> if (value != null)
> {
> file.Write(Program.CleanForCSV(value.ToString()));
> worksheet.Cells[r+3, c+1] = value; // Skip ahead to row #3, to allow
> space for headers
> }
>
> if (++c < numColumns) file.Write(','); // We don't want a comma after
> the last column
> }
> if (++r < numRows) file.WriteLine();
> }
>
> The odd iteration is the simplest way I could think of to efficiently
> avoid
> trailing commas in CSV.
> I've done some simple profiling at the procedure level, and there's no
> single part of the export process that takes much longer than the rest.
> Can
> I copy data by row or even copy the content of the whole DataGridView? It
> seems like that should be possible, but I haven't seen where. Any ideas?
> Thanks!



 
Reply With Quote
 
gimme_this_gimme_that@yahoo.com
Guest
Posts: n/a
 
      14th Jul 2007
I absolutely agree with Tim. Also, look for a DoEvents method so you
don't hold up the operating system.

 
Reply With Quote
 
=?Utf-8?B?Sm9uT2ZBbGxUcmFkZXM=?=
Guest
Posts: n/a
 
      19th Jul 2007
"Tim" wrote:

> Since you're communicating between processes, a cell-by-cell transfer of a
> lot of data is going to be slow, since each call has significant overhead
> and you're making one call per cell value. Try building an array and
> filling the sheet in one step.
>
> Tim


I suppose I took that to be a bit self-evident. What I need to know
is, how can I move data from a DataGridView to Excel en bloc? The data is
populated in C#, there's no bound data source I can access. I've gone over
the DataGridView and DataGridViewRow classes, and can't find a property or
method along the lines of "object[] Values". On the receiving side, in
Excel, the simple task of selecting a single row is maddeningly slippery.
"worksheet.Cells"? "worksheet.Range[0,0,numColumns,numRows]"?
"worksheet.Rows[n]"? None of the above, that would be too easy!
All the examples I can find on Google have used a bound data source, or
other workarounds like CSV or XML. Surely this isn't so difficult? It ought
to be as simple as "worksheet.Range[0,0,100,100].Values = grid.Values"!
 
Reply With Quote
 
Tim Williams
Guest
Posts: n/a
 
      19th Jul 2007
I'm not familiar with c# or .NET in general, but there must be a way to
access the values used to populate your datagrid.
Google groups had some promising stuff.

In VBA you can populate an entrire range from an array like this:

'************
Sub Tester()
Dim x, y
Dim arr(1 To 10, 1 To 10) as Integer


For x = 1 To 10
For y = 1 To 10
arr(x, y) = ((x - 1) * 10) + y
Next y
Next x

ActiveSheet.Range("A1").Resize(10, 10).Value = arr

End Sub
'************

ActiveSheet.Range("A1").Resize(10, 10).Value = arr
is equivalent to
ActiveSheet.Cells(1,1).Resize(10, 10).Value = arr

or

With ActiveSheet
.Range(.Cells(1,1), .Cells(10,10)).Value = arr
End With

a single row is referred to as

ActiveSheet.Rows(1)



Tim


"JonOfAllTrades" <(E-Mail Removed)> wrote in message
news:87FA1CD4-E8EF-4A56-9E54-(E-Mail Removed)...
> "Tim" wrote:
>
>> Since you're communicating between processes, a cell-by-cell transfer of
>> a
>> lot of data is going to be slow, since each call has significant overhead
>> and you're making one call per cell value. Try building an array and
>> filling the sheet in one step.
>>
>> Tim

>
> I suppose I took that to be a bit self-evident. What I need to know
> is, how can I move data from a DataGridView to Excel en bloc? The data is
> populated in C#, there's no bound data source I can access. I've gone
> over
> the DataGridView and DataGridViewRow classes, and can't find a property or
> method along the lines of "object[] Values". On the receiving side, in
> Excel, the simple task of selecting a single row is maddeningly slippery.
> "worksheet.Cells"? "worksheet.Range[0,0,numColumns,numRows]"?
> "worksheet.Rows[n]"? None of the above, that would be too easy!
> All the examples I can find on Google have used a bound data source,
> or
> other workarounds like CSV or XML. Surely this isn't so difficult? It
> ought
> to be as simple as "worksheet.Range[0,0,100,100].Values = grid.Values"!



 
Reply With Quote
 
=?Utf-8?B?Sm9uT2ZBbGxUcmFkZXM=?=
Guest
Posts: n/a
 
      19th Jul 2007
"Tim Williams" wrote:

> I'm not familiar with c# or .NET in general, but there must be a way to
> access the values used to populate your datagrid.
> Google groups had some promising stuff.
>
> In VBA you can populate an entrire range from an array like this:
>
> '************
> Sub Tester()
> Dim x, y
> Dim arr(1 To 10, 1 To 10) as Integer
>
>
> For x = 1 To 10
> For y = 1 To 10
> arr(x, y) = ((x - 1) * 10) + y
> Next y
> Next x
>
> ActiveSheet.Range("A1").Resize(10, 10).Value = arr
>
> End Sub
> '************
>
> ActiveSheet.Range("A1").Resize(10, 10).Value = arr
> is equivalent to
> ActiveSheet.Cells(1,1).Resize(10, 10).Value = arr
>
> or
>
> With ActiveSheet
> .Range(.Cells(1,1), .Cells(10,10)).Value = arr
> End With
>
> a single row is referred to as
>
> ActiveSheet.Rows(1)
>
> Tim


Now THAT would be convenient! Doing this in C# is not nearly that
straightforward. There's no Resize() function in C#, and the Rows() function
doesn't work that way. There's a get_Range(Cell1, Cell2) function, but it
doesn't take Cell objects as parameters! I guess COM doesn't allow for
method overloading, though since everything's passed as objects Excel should
be able to interrogate the parameters and interpret them correctly as strings
or Cells. I got this much to work:

string topLeft = "A1";
string bottomRight = char.ConvertFromUtf32(65 + numColumns - 1) +
numRows.ToString(); // 65 is ASCII for 'A', didncha know?
Range range = worksheet.get_Range(topLeft, bottomRight);

Later I found the get_Resize() function; looks like this is a known
workaround, KB 824004.
Building the array is much simpler, but my code is still not right to
actually push the data into Excel. KB 302096 uses
range.set_Value(Missing.Value, array), where array is an array of longs or
strings. The MS example uses [row][column], but I think that's wrong, other
sources indicate it's [column][row]. Trying to use set_Value, I keep getting
error "Specified array was not of the expected type."
I've tried object arrays and string arrays. I've tried specifying
RangeValueDataType, and I've tried using Type.Missing or
System.Reflection.Missing.Value. I've tried flipping the axis of my array.
I think I've tried every combination of these settings.
Clearly I'm missing something. Any ideas? If it can be done in
VB.NET, it can be done in C#, I'm sure.
 
Reply With Quote
 
Tim Williams
Guest
Posts: n/a
 
      19th Jul 2007
Sorry, .NET is new to me: I had assumed that when automating Excel you could
use syntax similar to VB[A] but it appears that's not the case.

Tim


"JonOfAllTrades" <(E-Mail Removed)> wrote in message
news:5B475693-1945-4266-9E6A-(E-Mail Removed)...
> "Tim Williams" wrote:
>
>> I'm not familiar with c# or .NET in general, but there must be a way to
>> access the values used to populate your datagrid.
>> Google groups had some promising stuff.
>>
>> In VBA you can populate an entrire range from an array like this:
>>
>> '************
>> Sub Tester()
>> Dim x, y
>> Dim arr(1 To 10, 1 To 10) as Integer
>>
>>
>> For x = 1 To 10
>> For y = 1 To 10
>> arr(x, y) = ((x - 1) * 10) + y
>> Next y
>> Next x
>>
>> ActiveSheet.Range("A1").Resize(10, 10).Value = arr
>>
>> End Sub
>> '************
>>
>> ActiveSheet.Range("A1").Resize(10, 10).Value = arr
>> is equivalent to
>> ActiveSheet.Cells(1,1).Resize(10, 10).Value = arr
>>
>> or
>>
>> With ActiveSheet
>> .Range(.Cells(1,1), .Cells(10,10)).Value = arr
>> End With
>>
>> a single row is referred to as
>>
>> ActiveSheet.Rows(1)
>>
>> Tim

>
> Now THAT would be convenient! Doing this in C# is not nearly that
> straightforward. There's no Resize() function in C#, and the Rows()
> function
> doesn't work that way. There's a get_Range(Cell1, Cell2) function, but it
> doesn't take Cell objects as parameters! I guess COM doesn't allow for
> method overloading, though since everything's passed as objects Excel
> should
> be able to interrogate the parameters and interpret them correctly as
> strings
> or Cells. I got this much to work:
>
> string topLeft = "A1";
> string bottomRight = char.ConvertFromUtf32(65 + numColumns - 1) +
> numRows.ToString(); // 65 is ASCII for 'A', didncha know?
> Range range = worksheet.get_Range(topLeft, bottomRight);
>
> Later I found the get_Resize() function; looks like this is a known
> workaround, KB 824004.
> Building the array is much simpler, but my code is still not right to
> actually push the data into Excel. KB 302096 uses
> range.set_Value(Missing.Value, array), where array is an array of longs or
> strings. The MS example uses [row][column], but I think that's wrong,
> other
> sources indicate it's [column][row]. Trying to use set_Value, I keep
> getting
> error "Specified array was not of the expected type."
> I've tried object arrays and string arrays. I've tried specifying
> RangeValueDataType, and I've tried using Type.Missing or
> System.Reflection.Missing.Value. I've tried flipping the axis of my
> array.
> I think I've tried every combination of these settings.
> Clearly I'm missing something. Any ideas? If it can be done in
> VB.NET, it can be done in C#, I'm sure.



 
Reply With Quote
 
gimme_this_gimme_that@yahoo.com
Guest
Posts: n/a
 
      20th Jul 2007
You don't need resize.

Try something more like this.

Set objwb = objXL.Workbooks.Add
Set objws = ExcelAddSheet("ActiveDirectory",DARK_BLUE)
Set objXL = CreateObject("Excel.Application")
objXL.Visible = True
data = Array("fasdfa","asdfasdf","asdfasdafd")
objws.Range(objws.Cells(1,1),objws.Cells(1,3)).Value = data

Also, an Excel statement such as this one inserts a two dimensional
array into a Worksheet
where arr is an array with 5 rows and three columns:

objws.Range("A1:C5").Value =
Application.Transpose(Application.Transpose(arr))

 
Reply With Quote
 
Ayman Absi
Guest
Posts: n/a
 
      3rd Aug 2007
I have the following code in VB.net with very good performance I think
you can convert it easly to C#:

Private Sub exportToExcel()
Dim xlApp As Object
Dim xlWb As Object
Dim xlWs As Object

Dim data(1)() 'two dim array (Dynamic)
Dim fldCount As Integer
Dim recCount As Long
Dim iCol As Integer
Dim iRow As Integer

' Create an instance of Excel and add a workbook
xlApp = CreateObject("Excel.Application")
xlWb = xlApp.Workbooks.Add
xlWs = xlWb.Worksheets("Sheet1")

' Copy field names to the first row of the worksheet
fldCount = DataGridView1.ColumnCount
ReDim data(0)(fldCount)
For iCol = 1 To fldCount
xlWs.Cells(1, iCol).Value = DataGridView1.Columns(iCol -
1).HeaderText
Next

' Copy data to the rest rows of the worksheet
recCount = DataGridView1.Rows.Count
For iRow = 2 To recCount
For iCol = 1 To fldCount
data(0)(iCol - 1) = DataGridView1.Rows(iRow -
1).Cells(iCol - 1).Value
Next
xlWs.Range(xlWs.Cells(iRow, 1), xlWs.Cells(iRow, iCol -
1)).Value = data(0)
Next

' Auto-fit the column widths and row heights
xlApp.Selection.CurrentRegion.Columns.AutoFit()
xlApp.Selection.CurrentRegion.Rows.AutoFit()

' Display Excel and give user control of Excel's lifetime
xlApp.Visible = True
xlApp.UserControl = True

' Release Excel references
xlWs = Nothing
xlWb = Nothing
xlApp = Nothing

End Sub

 
Reply With Quote
 
 
 
Reply

Thread Tools
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Very slow Visual Basic code execution in new Excel 2007 =?Utf-8?B?Sm9obkpvaG4=?= Microsoft Excel Programming 8 7th Oct 2009 09:45 PM
Excel 2007 ThisWorkbook code is slow PCLIVE Microsoft Excel Programming 0 3rd Apr 2009 04:55 PM
My excel worksheet to slow for editing - suggestions? vstrouse Microsoft Excel Misc 2 19th Mar 2009 12:15 AM
Very slow MDE & MDB response... suggestions? Gary Microsoft Access Getting Started 2 14th Sep 2004 01:54 PM
Slow code execution when Excel 2000 is in the background Tanner Microsoft Excel Programming 0 24th Mar 2004 12:47 PM


Features
 

Advertising
 

Newsgroups
 


All times are GMT +1. The time now is 10:36 AM.