anmcgrath / BlazorDatasheet

Simple excel-like datasheet Blazor component
MIT License
163 stars 40 forks source link

RemoveRowsOrColumsAndShift Throws: System.OverflowException: 'Arithmetic operation resulted in an overflow.' #82

Closed ADefWebserver closed 3 months ago

ADefWebserver commented 3 months ago

This happens when I try to delete any row. I can't reproduce this with anything but my own code :(

https://github.com/ADefWebserver/BlazorDatasheet/blob/main/src/BlazorDatasheet.SharedPages/Pages/DataEditor/DataEditor.razor

Image 001

Any ideas?

ADefWebserver commented 3 months ago

The only thing I think is different is I did add a custom renderer to my project.

ADefWebserver commented 3 months ago

I removed the custom renderer and it still throws the same error. I'm basically stuck :(

This is what Copilot says...

image

anmcgrath commented 3 months ago

I'll have a look. I made some changes last week to row/column removals that may have caused this.

ADefWebserver commented 3 months ago

I found my problem:

sheet.Cells.SetType(new ColumnRegion(i), objDatabaseColumn.ColumnType);

If I take this line out the problem goes away. I suspect ColumnRegion(i) is creating the huge value.

The reason I put it in is that it allows my custom renderer to show up on new rows;

image

My full code: https://github.com/ADefWebserver/BlazorDatasheet/blob/main/src/BlazorDatasheet.SharedPages/Pages/DataEditor/DataEditor.razor

private void LoadTableHeadersAndData(List<DTODatabaseColumn> paramDatabaseColumns, DataTable paramDataTable)
 {
     // Create sheet with the number of columns
     sheet = new Sheet(paramDataTable.Rows.Count, paramDatabaseColumns.Count);

     // Turn off history
     sheet.BatchUpdates();
     sheet.Commands.PauseHistory();

     // Hide the _Id column
     sheet.Columns.SetWidth(0, 0);

     int i = 0;
     foreach (DTODatabaseColumn objDatabaseColumn in paramDatabaseColumns)
     {
         // Set the column headings
         sheet.Columns.SetHeadings(i, i, objDatabaseColumn.ColumnName);

         // Set the column types
         // *** If I take this out the problem goes away ***
         sheet.Cells.SetType(new ColumnRegion(i), objDatabaseColumn.ColumnType);

         if (UseValidation)
         {
             // Integer Validator
             if (objDatabaseColumn.ColumnType.Contains("int"))
             {
                 sheet.Validators.Add(new ColumnRegion(i), new NumberValidator(false));
             }

             // Length Validator
             if (objDatabaseColumn.ColumnLength > 0)
             {
                 if (objDatabaseColumn.ColumnType.Contains("char"))
                 {
                     sheet.Validators.Add(new ColumnRegion(i), new LengthValidator(objDatabaseColumn.ColumnLength, true));
                 }
             }
         }

         i++;
     }

     // Load the data into the sheet
     int ii = 0;
     foreach (DataRow dataRow in paramDataTable.Rows)
     {
         i = 0;
         foreach (DTODatabaseColumn objDatabaseColumn in paramDatabaseColumns)
         {
             // Set the cell value
             sheet.Cells[ii, i].Value = GetCellValue(dataRow[i].ToString(), objDatabaseColumn.ColumnType);

             if (objDatabaseColumn.IsPrimaryKey)
             {
                 // Set the cell to read only if it is a primary key
                 sheet.Cells[ii, i].Format = new CellFormat() { IsReadOnly = true, BackgroundColor = "lightgrey" };
             }

             i++;
         }

         ii++;
     }

     // Wire up a method to catch cell changes
     sheet.Cells.CellsChanged += CellChanged;

     // Wire up a method to catch row changes
     // Do not allow the last row to be deleted
     sheet.Rows.RowRemoved += (sender, args) =>
     {
         // Turn off history
         sheet.BatchUpdates();
         sheet.Commands.PauseHistory();

         if (sheet.NumRows == 0)
         {
             sheet.Rows.InsertRowAt(0);
         }

         // Turn off history
         sheet.EndBatchUpdates();
         sheet.Commands.ResumeHistory();
     };

     // Turn on history
     sheet.EndBatchUpdates();
     sheet.Commands.ResumeHistory();
 }
anmcgrath commented 3 months ago

Thanks, adding as a column region is the correct way to add the type, I had a silly mistake whereby I was trying to sum areas of column/row regions which caused the overflow. Should be fixed now.

ADefWebserver commented 3 months ago

@anmcgrath - Fixed! Thank you so much for fixing this so fast. Normally I would diagnose and provide a proposed solution, but it would have taken me several weeks to study and understand the complexities of how this code works. This is a REALLY advanced control. It took all my free time this week to comprehend how the custom renderer works and that is actually straightforward once you understand it :)

anmcgrath commented 3 months ago

No worries. I think a lot of the complexity in the data structures comes from having to implement undo/redo which I've found really hard.

Yeah sorry it took you so long for the custom renderer, it would help if I had some better documentation for the project, which I'm planning on putting together.