Home » excel » c# – ListObject.Resize() makes DataBodyRange null when row count == 1

c# – ListObject.Resize() makes DataBodyRange null when row count == 1

Posted by: admin April 23, 2020 Leave a comment

Questions:

I am trying to reset the number of columns in an Excel ListObject. I know you can add and remove columns one-by-one, but I want to avoid unnecessary loops. I instead decided to resize the ListObject using the Resize method.

Here is the code that I am using (where OutputCasesTable is the ListObject):

OutputCasesTable.DataBodyRange.Value2 = "";
OutputCasesTable.Resize(OutputCasesTable.Range.Resize[ColumnSize: CaseCount]);
OutputCasesTable.DataBodyRange.Value2 = OutputCasesAray;

The above lines of code appear to work perfectly, however if the ListObject only contains 1 row of data, the DataBodyRange of the ListObject becomes null on the second line – producing an error when I try to change its cell’s value. The row in excel still appears to be present.

The MSDN documentation says the following:
“The header must remain in the same row and the resulting list must overlap the original list. The list must contain a header row and at least one row of data.”

Now I understand that “one row of data” implies that the row contains values – so the cause of the error here must be that the DataBodyRange cells all contain no value (“”). However, a table with two data rows containing “” still doesn’t have a row with data, does it?

I know there are many ways of accomplishing this task, but I want to understand why this happens.

Temporary Solution:
Replaced the code to only set the values to empty strings in columns that will be removed (columns above the new column count). All other columns will be replaced:

if(OutputCasesTable.ListColumns.Count - CaseCount > 0) 
    OutputCasesTable.DataBodyRange.Offset[ColumnOffset: CaseCount].Resize[ColumnSize: OutputCasesTable.ListColumns.Count - CaseCount].Value2 = "";
OutputCasesTable.Resize(OutputCasesTable.Range.Resize[ColumnSize: CaseCount]);
OutputCasesTable.DataBodyRange.Value2 = OutputCasesAray;

Personally I prefer looking at the first solution!

Is there anything I can do make it work with empty strings? Or do you have a better solution?

Best regards,

How to&Answers:

The Resize operation is the piece that kills the DataBodyRange, and clearly there’s some internal logic that Resize uses, along the lines of “if there is only one row, and all the cells are empty, remove all the data rows. If there is more than one row, don’t remove any”.

I agree that this logic is a bit confounding. If your question is why did Microsoft implement it this way, I’d argue that although it’s inconsistent, it’s perhaps tidier in a way – it appears to the model that you’re working with an empty table, and there’s no way for the model to tell the difference graphically (it’s not possible for a table to just have a header row).

When Resize turns up to do its work and finds a single-row blank table, it can’t tell whether you have a zero-row table or a single-row table with empty strings. If it arrives and finds two empty rows, that’s unambiguous (they must be meaningful rows).

For the workaround portion of your question, I’d suggest a tidier solution of just checking the ListRows.Count property, and adding one if necessary. Note that you can also use Clear instead of setting Value2 to blank; for me it reads as more self-explanatory.

OutputCasesTable.DataBodyRange.Clear();
OutputCasesTable.Resize(OutputCasesTable.Range.Resize[ColumnSize: CaseCount]);
if (OutputCasesTable.ListRows.Count == 0) OutputCasesTable.ListRows.Add();
OutputCasesTable.DataBodyRange.Value2 = OutputCasesAray;