unvell / ReoGrid

Fast and powerful .NET spreadsheet component, support data format, freeze, outline, formula calculation, chart, script execution and etc. Compatible with Excel 2007 (.xlsx) format and working on .NET 3.5 (or client profile), WPF and Android platform.
https://reogrid.net
MIT License
1.32k stars 390 forks source link

Painting error #439

Open CmeFrog opened 2 years ago

CmeFrog commented 2 years ago

Hello again Jingwood. I hope you have made progress on my previous issue #389. I am sad to say that I have another bug to report. I am using ReoGrid to display a work schedule. In the grid the rows are resources (people, outside vendors, etc) that perform work. The columns are time periods. I paint each sales order on the grid so that managers can see what resources are being used to work on which sales order at a particular time. Each order is painted into the appropriate cells based on the resource used and the dates the order is being worked on. Each order has a color and the sales order number is also shown. Most orders require work at multiple resources so one can follow a particular order's work flow from resource to resource easily. If based on the schedule data an order will be completed after its due date I paint a red hatch pattern over all the order's work making it easy for managers to identify problem orders that require their attention.

The rows are sorted based on the resource name so it is easy to find the resource you are looking for. Sometimes I need to add a new row if for instance the time period is hours and one order ends on the half hour and then another one starts. So I first sort the schedule data based on resource name and then work start time. As I paint the orders if a cell is already used by another order I add a new row immediately below it and then paint the order's work.

That is the context. Now for the issue. It involves using a WorksheetRangeStyle. Here is the code I use for the hatch pattern when painting the work done at a resource for an order. If the order's finish date is later than its due date the hatch pattern is applied.

private void SetRangeStyleFlagsSchedule(unvell.ReoGrid.Worksheet sheet, long orderID, string rangeAddress) { sheet.SetRangeStyles(rangeAddress, new WorksheetRangeStyle { // style item flag Flag = PlainStyleFlag.HorizontalAlign, // style item HAlign = ReoGridHorAlign.Center }); if (dictSchedule[orderID].FinishDate.Date > dictSchedule[orderID].DueDate.Date) { sheet.SetRangeStyles(rangeAddress, new WorksheetRangeStyle { // style item flag Flag = PlainStyleFlag.FillPattern | PlainStyleFlag.FillPatternColor, // style item FillPatternColor = Color.Red, FillPatternStyle = unvell.ReoGrid.Graphics.HatchStyles.Vertical }); } }

I have attached a screenshot that shows the problem. In the image below only order SO3 will be completed after its due date. All other orders will be finished before their due date. However parts of SO1, SO2, and SO4 have the hatch style applied. I have tried to figure out what triggers the error. Then I noticed there is something different about SO3 compared to the other orders. The work flow of the product that SO3 is for goes from Res 4 to Res 6 to Res 7 to Res 3. The resources are not in alphabetical order. All the other orders have a work flow through the resources in alphabetical order. For instance Res3 to Res 4 to Res 5 to Res 7. Here is the image - PaintedInResourceOrder1

So because the schedule data is sorted on resource name the last step in the work flow (Res 3) for order SO3 is painted first and then the next step painted is earlier in time. I wondered if painting the last step followed by the earlier ones is causing the painting error. To see if it made a difference I took the same schedule data and sorted it on start time only before painting. Here is an image of the resulting grid - PaintedInStartDateOrder1

You notice that the resource names in the row headers are no longer in alphabetical order because the order in which the schedule work was painted is not based on resource name as the primary sort. Res 3 is the last row whereas before it was the first. Since the schedule data is sorted by start time the order in which the schedule data was painted is done moving from earlier start times to later ones (left to right on the grid). You can see now only SO3 has the red hatch pattern indicating it will be completed past the due date. That is the correct painting.

I am hoping I can work around this bug by painting the grid based on a start time only sort of the schedule data and then reordering the rows so the row headers are in alphabetical order. I want the rows headers (resource names) to be in alphabetical order so it is easy to locate a particular resource. I hope that hatch pattern will stay intact as the rows are rearranged. I am going to try using the following example as a guide and removing the code for borders since I have none -

// -1 means all rows (entire column) var range = new ReoGridRange(0, 0, -1, 1);

// set cells sample data and borders sheet[range] = new object[] { "A", "B", "C" }; sheet.SetRangeBorder(range, ReoGridBorderPos.All, ReoGridBorderStyle.SolidBlack);

// copy a range into memory (including data and borders) var pg = sheet.GetPartialGrid(range);

// copy to worksheet from memory (like paste) sheet.SetPartialGrid(new ReoGridRange(0, 3, -1, 1), pg);

// remove original range (like cut) sheet.RemoveRangeBorder(range, ReoGridBorderPos.All); sheet.DeleteRangeData(range);

Maybe the information I have given you provides a clue that helps you fix this bug. Looking forward to your next release. Any idea when that might be?

Regards, Jeff

jingwood commented 2 years ago

Hi Jeff, thanks for the report! It would be great if you can provide a sample code or sample project to show this bug. That will be helpful to fix it quickly.

CmeFrog commented 2 years ago

Hello Jingwood. In trying to provide some sample code for you I think I have really narrowed down the cause. Here is how to duplicate the issue -

  1. create a form of size 1286, 702
  2. add 3 ReoGrid controls of size 1228, 196
  3. add the code below

    public partial class Form1 : Form { List lstColors = new List() { Color.Yellow, Color.Cyan, Color.LawnGreen, Color.Tan };

    public Form1()
    {
        InitializeComponent();
    }
    
    private void Form1_Load(object sender, EventArgs e)
    {
        DataTable dt1 = CreateNewTable();
        DataTable dt2 = CreateNewTable();
        LoadDt1(dt1);
        unvell.ReoGrid.Worksheet sheet = reoGridControl1.CurrentWorksheet;
        sheet.RowCount = 1;
        PaintGrid1(dt1, sheet);
        LoadDt2(dt2);
        sheet = reoGridControl2.CurrentWorksheet;
        sheet.RowCount = 1;
        PaintGrid1(dt2, sheet);
        sheet = reoGridControl3.CurrentWorksheet;
        sheet.RowCount = 1;
        PaintGrid2(dt2, sheet);
    }
    
    private DataTable CreateNewTable()
    {
        DataTable dt = new DataTable();
        DataColumn dtCol;
    
        dtCol = new DataColumn();
        dtCol.DataType = typeof(int);
        dtCol.ColumnName = "StartCol";
        dt.Columns.Add(dtCol);
        dtCol = new DataColumn();
        dtCol.DataType = typeof(int);
        dtCol.ColumnName = "EndCol";
        dt.Columns.Add(dtCol);
        dtCol = new DataColumn();
        dtCol.DataType = typeof(int);
        dtCol.ColumnName = "ColorIndex";
        dt.Columns.Add(dtCol);
        dtCol = new DataColumn();
        dtCol.DataType = typeof(bool);
        dtCol.ColumnName = "ShowHatch";
        dt.Columns.Add(dtCol);
        return dt;
    }
    
    private void LoadDt1(DataTable dt)
    {
        DataRow dtRow;
    
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 0;
        dtRow["EndCol"] = 2;
        dtRow["ColorIndex"] = 0;
        dtRow["ShowHatch"] = true;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 2;
        dtRow["EndCol"] = 4;
        dtRow["ColorIndex"] = 0;
        dtRow["ShowHatch"] = true;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 4;
        dtRow["EndCol"] = 6;
        dtRow["ColorIndex"] = 1;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 6;
        dtRow["EndCol"] = 8;
        dtRow["ColorIndex"] = 1;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 8;
        dtRow["EndCol"] = 10;
        dtRow["ColorIndex"] = 2;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 10;
        dtRow["EndCol"] = 12;
        dtRow["ColorIndex"] = 2;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 12;
        dtRow["EndCol"] = 14;
        dtRow["ColorIndex"] = 3;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 14;
        dtRow["EndCol"] = 16;
        dtRow["ColorIndex"] = 3;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
    }
    
    private void LoadDt2(DataTable dt)
    {
        DataRow dtRow;
    
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 4;
        dtRow["EndCol"] = 6;
        dtRow["ColorIndex"] = 0;
        dtRow["ShowHatch"] = true;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 6;
        dtRow["EndCol"] = 8;
        dtRow["ColorIndex"] = 0;
        dtRow["ShowHatch"] = true;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 2;
        dtRow["EndCol"] = 4;
        dtRow["ColorIndex"] = 1;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 4;
        dtRow["EndCol"] = 6;
        dtRow["ColorIndex"] = 1;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 3;
        dtRow["EndCol"] = 5;
        dtRow["ColorIndex"] = 2;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 5;
        dtRow["EndCol"] = 7;
        dtRow["ColorIndex"] = 2;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 4;
        dtRow["EndCol"] = 6;
        dtRow["ColorIndex"] = 3;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 6;
        dtRow["EndCol"] = 8;
        dtRow["ColorIndex"] = 3;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
    }
    
    private void PaintGrid1(DataTable dt, unvell.ReoGrid.Worksheet sheet)
    {
        unvell.ReoGrid.Cell currCell;
        DataRow dtRow;
        int idxRow;
        Color colorBkgd;
        bool showHatch;
        string rangeAddress;
        unvell.ReoGrid.CellPosition posStart;
        unvell.ReoGrid.CellPosition posEnd;
    
        for (int idx = 0; idx < dt.Rows.Count; idx++)
        {
            if (idx > 0)
                sheet.AppendRows(1);
            dtRow = dt.Rows[idx];
            idxRow = sheet.RowCount - 1; // (int)dtRow["RowIndex"];
            colorBkgd = lstColors[(int)dtRow["ColorIndex"]];
            showHatch = (bool)dtRow["ShowHatch"];
            for (int idxCol = (int)dtRow["StartCol"]; idxCol <= (int)dtRow["EndCol"]; idxCol++)
            {
                currCell = sheet.Cells[idxRow, idxCol];
                currCell.Style.BackColor = colorBkgd;
            }
            if (showHatch)
            {
                posStart = new unvell.ReoGrid.CellPosition(idxRow, (int)dtRow["StartCol"]);
                posEnd = new unvell.ReoGrid.CellPosition(idxRow, (int)dtRow["EndCol"]);
                rangeAddress = $"{posStart.ToAddress()}:{posEnd.ToAddress()}";
                sheet.SetRangeStyles(rangeAddress, new unvell.ReoGrid.WorksheetRangeStyle
                {
                    // style item flag
                    Flag = unvell.ReoGrid.PlainStyleFlag.FillPattern | unvell.ReoGrid.PlainStyleFlag.FillPatternColor,
                    // style item
                    FillPatternColor = Color.Red,
                    FillPatternStyle = unvell.ReoGrid.Graphics.HatchStyles.Vertical
                });
            }
        }
    }
    
    private void PaintGrid2(DataTable dt, unvell.ReoGrid.Worksheet sheet)
    {
        unvell.ReoGrid.Cell currCell;
        DataRow dtRow;
        int idxRow;
        Color colorBkgd;
        bool showHatch;
        string rangeAddress;
        unvell.ReoGrid.CellPosition posStart;
        unvell.ReoGrid.CellPosition posEnd;
    
        for (int idx = 0; idx < dt.Rows.Count; idx++)
        {
            dtRow = dt.Rows[idx];
            switch (idx)
            {
                case 0:
                    idxRow = 0;
                    break;
                case 1:
                    sheet.InsertRows(sheet.RowCount, 1);
                    idxRow = 1;
                    break;
                default:
                    sheet.InsertRows(sheet.RowCount - 1, 1);
                    idxRow = sheet.RowCount - 2;
                    break;
            }
            colorBkgd = lstColors[(int)dtRow["ColorIndex"]];
            showHatch = (bool)dtRow["ShowHatch"];
            for (int idxCol = (int)dtRow["StartCol"]; idxCol <= (int)dtRow["EndCol"]; idxCol++)
            {
                currCell = sheet.Cells[idxRow, idxCol];
                currCell.Style.BackColor = colorBkgd;
            }
            if (showHatch)
            {
                posStart = new unvell.ReoGrid.CellPosition(idxRow, (int)dtRow["StartCol"]);
                posEnd = new unvell.ReoGrid.CellPosition(idxRow, (int)dtRow["EndCol"]);
                rangeAddress = $"{posStart.ToAddress()}:{posEnd.ToAddress()}";
                sheet.SetRangeStyles(rangeAddress, new unvell.ReoGrid.WorksheetRangeStyle
                {
                    // style item flag
                    Flag = unvell.ReoGrid.PlainStyleFlag.FillPattern | unvell.ReoGrid.PlainStyleFlag.FillPatternColor,
                    // style item
                    FillPatternColor = Color.Red,
                    FillPatternStyle = unvell.ReoGrid.Graphics.HatchStyles.Vertical
                });
            }
        }
    }

    }

It seems the issue is that neither AppendRows or InsertRows actually append or insert a new row. The row appended or inserted is a kind of derived row inheriting some of the properties of the row where the appending or inserting was done.

In the code I tried to simulate my schedule management app. I basically created 4 orders each with work done at 2 resources. The resources are rows so that imagine the first row is Res 1, the second row is Res 2, the third row is Res 3, and so on. Each order has its own color. Run the code and notice that in the first grid all looks fine. If you look at the data being displayed only the first order (it is colored yellow) has the hatch pattern. This is because none of the other orders are displayed in first three columns. These are the columns used to display the work in the row (the first row) from which the appending starts. In the second grid all I did was change the columns used to display the work from the first order. The work in the first row is now in columns which are also used to display work for some of the other orders. You can see that in the others rows for the other 3 orders, which were appended, if they use the same columns as used on the first row they now have the hatch pattern. Even though if you look at the painting code they should not because for the other 3 orders showHatch is false. The only difference between the second and third grids is that I used InsertRows instead of AppendRows to see if the same error occurs.

So now the work around for this error is easier for me. I will have to make 2 passes to paint my schedule gird. In the first pass I will draw the grid and display the colors indicating the work done on the different orders. Once that is finished and any insertions required have been done then I will make a second pass to add the hatch pattern for orders that will be completed past their due date.

I know that when I am asked to estimate when some coding work will be done I am wrong 99% of the time. It always seems to take longer than my estimate even though I have padded my estimate with what I was 100% sure was sufficient margin for error. When I got your message about issue #389 saying that you would fix the bug in some days time I promised my boss that I would release something by the end of the year. I had other work that needed to be done so the end of year estimate was to allow for time to do that work. Well the end of the year is fast approaching. I can do a work around of not allowing an order's work to be changed using the mouse. In my code I had written it allowed the user to move work or change its start/finish times with the mouse. In a work around instead if the user clicks on some order's work I will open a dialog box and they can manually enter in a new start and stop date or resource for work. It will be kind of clunky compared to being able to do it using the mouse but until screen scrolling in the left or up directions using the mouse is fixed I can not use that code. So do you think your next release will be before the end of the year? If not I will have to comment out my mouse code and add dialog box code.

You have a great control here and your efforts at improvement are appreciated. Once everything works and my app is released I will ask my boss if the company can put a little money in your pocket with a donation.

Regards, Jeff

CmeFrog commented 2 years ago

Jingwood,

I don't know if this helps but prior to delaying the painting of the hatch pattern , which is the work around I eventually did, I tried sheet.RemoveRangeStyles(new RangePosition(targetRow, 0, 1, targetCols, PlainStyleFlag.All); on the new row immediately after it was appended or inserted. It did not work, the hatch pattern still remained.

The way it is now the SetRangeStyles command is broken. Or to say it more precisely, the absence of a SetRangeStyles command is broken.

Regards, Jeff

jingwood commented 2 years ago

Thanks, did you mean that the hatch pattern style cannot be removed from a worksheet. The RemoveRangeStyles doesn't work as you expected?

CmeFrog commented 2 years ago

Thanks for you reply jingwood. The real issue is that when you add or insert rows you do not get a new row. You get a row that has some properties it inherits, like the range style fill pattern in this case, There may be more but this is one I see in my project. The assumption one has when you add or insert a row that it is a clean new row. If you run my sample code you will see that you definitely do not get a clean new row. Even though the code only sets a hatch pattern fill on two rows (the two rows of the yellow order) in the last 2 of the 3 grids the hatch pattern has somehow mysteriously been acquired by all cells below the first row yellow cells. If you look at the code it is clear that it only sets the fill pattern for the yellow order. No fill pattern is ever set for any of the other orders. But the code make no difference in what is displayed in this case.

I thought that as a temporary fix I could maybe remove range styles after a row is added or inserted. However it made no difference, the hatch pattern still remains on parts of the other orders which in code no hatch pattern had been specified.

In fact the only reason there is no hatch pattern on orders other than yellow one in the first grid in my sample code is not because of what I have coded. It is because none of the other orders have cells below the yellow cells on the first row. That is the only difference between the orders in the first and second grid. The code to load those two grids calls the same method. The only difference is in the data table, in the location of the yellow cells in the first row. You can see how just moving the location of one of the orders dramatically affects how the other orders are displayed regardless of code.

Regards, Jeff

CmeFrog commented 2 years ago

In my sample code I have 8 bars I wish to paint by setting the back color of certain cells. A bar is a series of connected cells with the same back color. In this case each bar is only one row high. Further I wish to divide the 8 bars into 4 groups with each group having 2 bars. At the top of the sample code a list of 4 colors is declared, one color for each group. To control the painting I built a datatable that has 4 columns.. They are the starting column index , the ending column index, the color list index, and a boolean to indicate whether or not to use the hatch fill pattern.

For the first grid I set the starting and ending column values of the first two datatable records so that they are painted as bars in the top left of the grid. Notice that in only these two records is the ShowHatch boolean set to true. ShowHatch for all the other 6 bars is set to false. Also notice the starting and ending column values for the other 6 bars are set such that they are not in the same columns as the bar on the top row. Then I call the method PaintGrid1 to paint the bars based on the datatable records.

For the second grid all I did was change the starting and ending column values for the first two datatable records. Now they are located not in the top left but in the top middle . Also see that some of the other bars are in some of the same columns as the bar in the top row. Then as before I call the method PaintGrid1 to paint the bars based on the datatable records.

You can see how different the second grid looks. How many bars now magically contain the hatch fill pattern even though they had their ShowHatch value set to false. In this case it did not matter that in code the hatch fill pattern was set on only the bars from the first two datatable records. What determined whether or not the hatch fill pattern was displayed for a cell on the other 6 bars was their grid location relative to the bar in the top row.

Grid 3 is using the same datatable as Grid 2 but instead of appending new rows it inserts them. I wanted to see if the bug affected both appends and inserts. It does. In both cases the "new" row that is created has some properties already set based on the row from where the insertion or deletion was done. This is clearly shown by the sample code.

So what I am requesting is that inserted or appended row be a clean new row. One shouldn't have to worry about what properties may be already set when the new row is created. Or maybe change the command name to "InsertPartialCloneOfNearbyRow" as a possible suggestion :)

CmeFrog commented 2 years ago

Hi jingwood. After thinking about how to make my sample code simpler I realized I don't need to have the bars put into 4 groups. So here is a revised sample code with only 4 bars instead of 8. I only did append rows but I would assume the insert rows also has the same bug as shown in my last sample code.

There are 5 grids on the form each one is 1228 X 138 in size. The form is 1286 X 871.

The first grid displays 4 bars, one in each row. The first row is added and it is painted with a red hatch pattern. The next 3 rows are appended and no PlainStyleFlag is set. You can see that the code does not determine if a hatch pattern is painted on the last 3 rows. Grid position, being in some of the same columns as the bar in the top row, controls whether or not the hatch pattern is painted.

In the second grind all is painted as in grid one except immediately after a new row is appended RemoveRangeStyles is called. You can see that has no effect on whether or not the hatch pattern is painted.

In the third grid all is painted as in grid one. However a black hatch pattern is applied immediately each new row is created. You can see that for the first time the appearance of the bars is as coded. You could actually read the code and predict what the bars look like.

In the fourth grid all is painted as in grid three expect that RemoveRangeStyles is called immediately after the black hatch is applied. You can see here that RemoveRangeStyles removed the black hatch pattern only. Even though RemoveRangeStyles was called with the PlainStyleFlag set to All. The red hatch pattern created by the bug seems completely invisible to RemoveRangeStyles.

The fifth grid is also one that the appearance could be predicted from the code. In this grid all is painted as in grid 3 except the color of the hatch pattern applied immediately after a new row is appended is the same color as the cell back color.

Please run the code and I think you can see the problem very easily.

Thanks, Jeff

Here is the simpler sample code -

public partial class Form1 : Form
{
    List<Color> lstColors = new List<Color>() { Color.Yellow, Color.Cyan, Color.LawnGreen, Color.Tan };

    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        DataTable dt = CreateNewTable();
        LoadDt(dt);
        unvell.ReoGrid.Worksheet sheet = reoGridControl1.CurrentWorksheet;
        sheet.RowCount = 1;
        PaintGrid1(dt, sheet);
        sheet = reoGridControl2.CurrentWorksheet;
        sheet.RowCount = 1;
        PaintGrid2(dt, sheet);
        sheet = reoGridControl3.CurrentWorksheet;
        sheet.RowCount = 1;
        PaintGrid3(dt, sheet);
        sheet = reoGridControl4.CurrentWorksheet;
        sheet.RowCount = 1;
        PaintGrid4(dt, sheet);
        sheet = reoGridControl5.CurrentWorksheet;
        sheet.RowCount = 1;
        PaintGrid5(dt, sheet);
    }

    private DataTable CreateNewTable()
    {
        DataTable dt = new DataTable();
        DataColumn dtCol;

        dtCol = new DataColumn();
        dtCol.DataType = typeof(int);
        dtCol.ColumnName = "StartCol";
        dt.Columns.Add(dtCol);
        dtCol = new DataColumn();
        dtCol.DataType = typeof(int);
        dtCol.ColumnName = "EndCol";
        dt.Columns.Add(dtCol);
        dtCol = new DataColumn();
        dtCol.DataType = typeof(int);
        dtCol.ColumnName = "ColorIndex";
        dt.Columns.Add(dtCol);
        dtCol = new DataColumn();
        dtCol.DataType = typeof(bool);
        dtCol.ColumnName = "ShowHatch";
        dt.Columns.Add(dtCol);
        return dt;
    }

    private void LoadDt(DataTable dt)
    {
        DataRow dtRow;

        dtRow = dt.NewRow();
        dtRow["StartCol"] = 4;
        dtRow["EndCol"] = 6;
        dtRow["ColorIndex"] = 0;
        dtRow["ShowHatch"] = true;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 2;
        dtRow["EndCol"] = 4;
        dtRow["ColorIndex"] = 1;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 5;
        dtRow["EndCol"] = 7;
        dtRow["ColorIndex"] = 2;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
        dtRow = dt.NewRow();
        dtRow["StartCol"] = 4;
        dtRow["EndCol"] = 6;
        dtRow["ColorIndex"] = 3;
        dtRow["ShowHatch"] = false;
        dt.Rows.Add(dtRow);
    }

    private void PaintGrid1(DataTable dt, unvell.ReoGrid.Worksheet sheet)
    {
        DataRow dtRow;

        for (int idx = 0; idx < dt.Rows.Count; idx++)
        {
            dtRow = dt.Rows[idx];
            if (idx > 0)
            {
                sheet.AppendRows(1);
            }
            PaintBarCellsBkgd(dtRow, sheet);
            ProcessHatchFlag(dtRow, sheet);
        }
        sheet.AppendRows(1);
        sheet["A5"] = "Rows are appended only";
    }

    private void PaintBarCellsBkgd(DataRow dtRow, unvell.ReoGrid.Worksheet sheet)
    {
        unvell.ReoGrid.Cell currCell;
        int idxRow = sheet.RowCount - 1;
        Color colorBkgd = lstColors[(int)dtRow["ColorIndex"]];
        for (int idxCol = (int)dtRow["StartCol"]; idxCol <= (int)dtRow["EndCol"]; idxCol++)
        {
            currCell = sheet.Cells[idxRow, idxCol];
            currCell.Style.BackColor = colorBkgd;
        }
    }

    private void ProcessHatchFlag(DataRow dtRow, unvell.ReoGrid.Worksheet sheet)
    {
        if ((bool)dtRow["ShowHatch"])
        {
            unvell.ReoGrid.CellPosition posStart = new unvell.ReoGrid.CellPosition(sheet.RowCount - 1, (int)dtRow["StartCol"]);
            unvell.ReoGrid.CellPosition posEnd = new unvell.ReoGrid.CellPosition(sheet.RowCount - 1, (int)dtRow["EndCol"]);
            string rangeAddress = $"{posStart.ToAddress()}:{posEnd.ToAddress()}";
            sheet.SetRangeStyles(rangeAddress, new unvell.ReoGrid.WorksheetRangeStyle
            {
                // style item flag
                Flag = unvell.ReoGrid.PlainStyleFlag.FillPattern | unvell.ReoGrid.PlainStyleFlag.FillPatternColor,
                // style item
                FillPatternColor = Color.Red,
                FillPatternStyle = unvell.ReoGrid.Graphics.HatchStyles.Vertical
            });
        }
    }

    private void PaintGrid2(DataTable dt, unvell.ReoGrid.Worksheet sheet)
    {
        DataRow dtRow;
        string rangeAddress;
        unvell.ReoGrid.CellPosition posStart;
        unvell.ReoGrid.CellPosition posEnd;
        int topRowStartCol = 0;
        int topRowEndCol = 0;

        for (int idx = 0; idx < dt.Rows.Count; idx++)
        {
            dtRow = dt.Rows[idx];
            if (idx > 0)
            {
                sheet.AppendRows(1);
                posStart = new unvell.ReoGrid.CellPosition(sheet.RowCount - 1, topRowStartCol);
                posEnd = new unvell.ReoGrid.CellPosition(sheet.RowCount - 1, topRowEndCol);
                rangeAddress = $"{posStart.ToAddress()}:{posEnd.ToAddress()}";
                sheet.RemoveRangeStyles(rangeAddress, unvell.ReoGrid.PlainStyleFlag.All);
            }
            else
            {
                topRowStartCol = (int)dtRow["StartCol"];
                topRowEndCol = (int)dtRow["EndCol"];
            }
            PaintBarCellsBkgd(dtRow, sheet);
            ProcessHatchFlag(dtRow, sheet);
        }
        sheet.AppendRows(1);
        sheet["A5"] = "Rows are appended and then RemoveRangeStyles called";
    }

    private void PaintGrid3(DataTable dt, unvell.ReoGrid.Worksheet sheet)
    {
        DataRow dtRow;
        string rangeAddress;
        unvell.ReoGrid.CellPosition posStart;
        unvell.ReoGrid.CellPosition posEnd;
        int topRowStartCol = 0;
        int topRowEndCol = 0;

        for (int idx = 0; idx < dt.Rows.Count; idx++)
        {
            dtRow = dt.Rows[idx];
            if (idx > 0)
            {
                sheet.AppendRows(1);
                posStart = new unvell.ReoGrid.CellPosition(sheet.RowCount - 1, topRowStartCol);
                posEnd = new unvell.ReoGrid.CellPosition(sheet.RowCount - 1, topRowEndCol);
                rangeAddress = $"{posStart.ToAddress()}:{posEnd.ToAddress()}";
                sheet.SetRangeStyles(rangeAddress, new unvell.ReoGrid.WorksheetRangeStyle
                {
                    // style item flag
                    Flag = unvell.ReoGrid.PlainStyleFlag.FillPattern | unvell.ReoGrid.PlainStyleFlag.FillPatternColor,
                    // style item
                    FillPatternColor = Color.Black,
                    FillPatternStyle = unvell.ReoGrid.Graphics.HatchStyles.Vertical
                });
            }
            else
            {
                topRowStartCol = (int)dtRow["StartCol"];
                topRowEndCol = (int)dtRow["EndCol"];
            }
            PaintBarCellsBkgd(dtRow, sheet);
            ProcessHatchFlag(dtRow, sheet);
        }
        sheet.AppendRows(1);
        sheet["A5"] = "Rows are appended and then black hatch pattern applied";
    }

    private void PaintGrid4(DataTable dt, unvell.ReoGrid.Worksheet sheet)
    {
        DataRow dtRow;
        string rangeAddress;
        unvell.ReoGrid.CellPosition posStart;
        unvell.ReoGrid.CellPosition posEnd;
        int topRowStartCol = 0;
        int topRowEndCol = 0;

        for (int idx = 0; idx < dt.Rows.Count; idx++)
        {
            dtRow = dt.Rows[idx];
            if (idx > 0)
            {
                sheet.AppendRows(1);
                posStart = new unvell.ReoGrid.CellPosition(sheet.RowCount - 1, topRowStartCol);
                posEnd = new unvell.ReoGrid.CellPosition(sheet.RowCount - 1, topRowEndCol);
                rangeAddress = $"{posStart.ToAddress()}:{posEnd.ToAddress()}";
                sheet.SetRangeStyles(rangeAddress, new unvell.ReoGrid.WorksheetRangeStyle
                {
                    // style item flag
                    Flag = unvell.ReoGrid.PlainStyleFlag.FillPattern | unvell.ReoGrid.PlainStyleFlag.FillPatternColor,
                    // style item
                    FillPatternColor = Color.Black,
                    FillPatternStyle = unvell.ReoGrid.Graphics.HatchStyles.Vertical
                });
                sheet.RemoveRangeStyles(rangeAddress, unvell.ReoGrid.PlainStyleFlag.All);
            }
            else
            {
                topRowStartCol = (int)dtRow["StartCol"];
                topRowEndCol = (int)dtRow["EndCol"];
            }
            PaintBarCellsBkgd(dtRow, sheet);
            ProcessHatchFlag(dtRow, sheet);
        }
        sheet.AppendRows(1);
        sheet["A5"] = "Rows are appended, black hatch pattern applied and then RemoveRangeStyles called";
    }

    private void PaintGrid5(DataTable dt, unvell.ReoGrid.Worksheet sheet)
    {
        DataRow dtRow;
        string rangeAddress;
        unvell.ReoGrid.CellPosition posStart;
        unvell.ReoGrid.CellPosition posEnd;
        int topRowStartCol = 0;
        int topRowEndCol = 0;

        for (int idx = 0; idx < dt.Rows.Count; idx++)
        {
            dtRow = dt.Rows[idx];
            if (idx > 0)
            {
                sheet.AppendRows(1);
                posStart = new unvell.ReoGrid.CellPosition(sheet.RowCount - 1, topRowStartCol);
                posEnd = new unvell.ReoGrid.CellPosition(sheet.RowCount - 1, topRowEndCol);
                rangeAddress = $"{posStart.ToAddress()}:{posEnd.ToAddress()}";
                sheet.SetRangeStyles(rangeAddress, new unvell.ReoGrid.WorksheetRangeStyle
                {
                    // style item flag
                    Flag = unvell.ReoGrid.PlainStyleFlag.FillPattern | unvell.ReoGrid.PlainStyleFlag.FillPatternColor,
                    // style item
                    FillPatternColor = lstColors[(int)dtRow["ColorIndex"]],
                    FillPatternStyle = unvell.ReoGrid.Graphics.HatchStyles.Vertical
                });
            }
            else
            {
                topRowStartCol = (int)dtRow["StartCol"];
                topRowEndCol = (int)dtRow["EndCol"];
            }
            PaintBarCellsBkgd(dtRow, sheet);
            ProcessHatchFlag(dtRow, sheet);
        }
        sheet.AppendRows(1);
        sheet["A5"] = "Rows are appended and then hatch pattern of matching color applied";
    }
}
CmeFrog commented 2 years ago

Hello jingwood. I have decided on the work around for this issue until it gets fixed. At first I just delayed the painting of the hatch pattern on late orders until all orders had been painted. But then I realized that will not solve the situation of when a manager changes the work done for an order. That may require that a row be inserted on the grid and then the issue could show up again if the row where is insertion is to be done has any late orders on it. They would have the red hatch pattern which would be inherited by the new inserted row. You saw in my sample code that appended and inserted rows are dirty and also that RemoveRangeStyles does not remove the range style so I can get a clean row. It appears the only way to always get an appended or inserted row to appear as new is to always paint a hatch pattern. So to effectively hide the issue my code now paints a red hatch pattern if the order is late and a hatch pattern that matches the cell back color if the order is not late. Every cell I paint must get a hatch pattern until this issue is corrected.

Luckily as you can see from my sample code the inherited hatch pattern on appended or inserted rows seems only to be visible if you apply a back color to a cell in the new row. If you just put in text or nothing at all in a cell the hatch pattern is not seen. So at least I do not have to put a hatch pattern on the whole new row, only the cells in the new row that I wish to have a back color.

Regards, Jeff