I have a DataGridView with a Contact column full of numbers. Each number can reoccur multiple times, or just once. I am trying to find a solution to re-colour each set of rows that contain matching numbers, but not recolour the ones with no duplicates. Example of the outcome I am trying to achieve:
<p style="color:green;">2</p>
<p style="color:green;">2</p>
<p style="color:red;">3</p>
<p style="color:red;">3</p>
123 <br><br>
321 <br>
<p style="color:yellow;">4</p>
<p style="color:yellow;">4</p>
<p style="color:red;">3</p>
<p style="color:yellow;">4</p>
Here is my code, I think the problem is where I am incrementing the "duplicateCount" integer for the switch statement as I need it to increment only after every row containing the same value is coloured, but could not figure out a way to do that. Hoping I am clear enough and someone can guide me in the right direction. Thanks in advance
public void HighlightDuplicates(DataGridView grv)
{
List<String> alreadydone = new List<String>();
int duplicateCount = 1;
for (int currentRow = 0; currentRow < grv.Rows.Count - 1; currentRow )
{
DataGridViewRow rowToCompare = grv.Rows[currentRow];
for (int otherRow = 0; otherRow < grv.Rows.Count-1; otherRow )
{
DataGridViewRow row = grv.Rows[otherRow];
bool duplicateRow = true;
string rowToCompareString0 = rowToCompare.Cells[2].Value.ToString();
string rowString0 = row.Cells[2].Value.ToString();
if (rowToCompare.Cells[2].Value.ToString() != row.Cells[2].Value.ToString())
{
duplicateRow = false;
continue;
}
if (duplicateRow && currentRow != otherRow && !alreadydone.Contains(rowToCompare.Cells[2].Value.ToString() rowToCompare))
{
switch (duplicateCount)
{
case 1:
rowToCompare.Cells[2].Style.BackColor = System.Drawing.Color.Red;
rowToCompare.Cells[2].Style.ForeColor = System.Drawing.Color.Black;
row.Cells[2].Style.BackColor = System.Drawing.Color.Red;
row.Cells[2].Style.ForeColor = System.Drawing.Color.Black;
alreadydone.Add(rowToCompare.Cells[2].Value.ToString() rowToCompare);
break;
case 2:
rowToCompare.Cells[2].Style.BackColor = System.Drawing.Color.Yellow;
rowToCompare.Cells[2].Style.ForeColor = System.Drawing.Color.Black;
row.Cells[2].Style.BackColor = System.Drawing.Color.Yellow;
row.Cells[2].Style.ForeColor = System.Drawing.Color.Black;
alreadydone.Add(rowToCompare.Cells[2].Value.ToString() rowToCompare);
break;
case 3:
rowToCompare.Cells[2].Style.BackColor = System.Drawing.Color.Green;
rowToCompare.Cells[2].Style.ForeColor = System.Drawing.Color.Black;
row.Cells[2].Style.BackColor = System.Drawing.Color.Green;
row.Cells[2].Style.ForeColor = System.Drawing.Color.Black;
alreadydone.Add(rowToCompare.Cells[2].Value.ToString() rowToCompare);
break;
default:
rowToCompare.Cells[2].Style.BackColor = System.Drawing.Color.Purple;
row.Cells[2].Style.BackColor = System.Drawing.Color.Purple;
alreadydone.Add(rowToCompare.Cells[2].Value.ToString() rowToCompare);
break;
}
}
}
duplicateCount ;
}
}
CodePudding user response:
You are trying to do too much in one go. Things get much easier when you split them up. First get the distinct values (using linq and from memory):
var distinctValues = grv.Rows.Select(r=>r.Cells[2].Value.ToString()).Distinct;
Then write a method to assign the colours:
Dictionary<string, System.Drawing.Color> AssignColours(IEnumerable<string> values)
{
// Add as many colours as you need here
System.Drawing.Color[] colours = new System.Drawing.Color[] {System.Drawing.Color.Red, System.Drawing.Color.Yellow, System.Drawing.Color.Green, System.Drawing.Color.Purple};
var result = new Dictionary<string, System.Drawing.Color>();
int currentColour = 0;
foreach (var s in values)
{
result[s] = colours[currentColour ];
}
return result;
}
And finally call the method and set the colour of the cells:
var colourDict = AssignColours(distinctValues);
for (int row = 0; row < grv.Rows.Count - 1; row )
{
var cell = grv.Rows[row].Cells[2];
var value = cell.Value.ToString();
var backColour = colourDict[value];
cell.Style.BackColor = backColour;
cell.Style.ForeColor = System.Drawing.Color.Black;
}
CodePudding user response:
It appears you may be over complicating things. It is unclear why your current code is using two for
loops for this. One for
loop will work and it will be less complicated.
The approach below simply loops through the rows in the grid and checks adjacent rows for equality. The only caveat here is that we need to color the first row FIRST. We know the first row will be colored since there is no “previous” row to compare it with.
Once this first row is colored, then we will loop through each row in the grid… HOWEVER, the for
loop will not iterate to the LAST row. The loop will iterate to the second to the last row. With each iteration of the loop, we will check the “second” row to see if it equals the “previous” row and if so, we can color the second rows cell with the same color. If the cell values are not equal, then we will simply change the color of that cell to the next color.
It is unknown how many “different” colors you may want to use and, in the example below I used four (4) different colors and if the number of “different” cell values is greater than four (4), then we will simply start over with the first color used. In other words, the first and fifth groups of rows with “different” values will be colored the same and will repeat for every group of five different cell values.
To help, we will create a simple method called SetCellColor
that will take an int curColor
and a DataGridViewCell cell
. In this method we will simply color the cell based on the given curColor
. This method may look something like…
private void SetCellColor(int curColor, DataGridViewCell cell) {
switch(curColor) {
case 1:
cell.Style.ForeColor = Color.Red;
cell.Style.BackColor = Color.Black;
break;
case 2:
cell.Style.ForeColor = Color.Black;
cell.Style.BackColor = Color.Yellow;
break;
case 3:
cell.Style.ForeColor = Color.Black;
cell.Style.BackColor = Color.Green;
break;
case 4:
cell.Style.ForeColor = Color.Wheat;
cell.Style.BackColor = Color.Purple;
break;
}
}
This method above will make it easier to color the cell when we compare the two row’s cell values. We will use the above method in the method below which loops through the grid rows as described above. Keep in mind we need to set the loop to go from row zero (0), to the “SECOND” to last row. NOTE: this assumes the grids AllowUsersToAddRows
property is set to false
. If it is set to true
then you will need to set the ending condition to Rows.Count – 2 to avoid a guaranteed null
exception.
private void ColorDuplicateCells() {
int curColorIndex = 1;
SetCellColor(curColorIndex, dataGridView1.Rows[0].Cells[2]);
for (int i = 0; i < dataGridView1.Rows.Count - 1; i ) {
if (dataGridView1.Rows[i].Cells[2].Value.ToString() == dataGridView1.Rows[i 1].Cells[2].Value.ToString()) {
SetCellColor(curColorIndex, dataGridView1.Rows[i 1].Cells[2]);
}
else {
curColorIndex ;
if (curColorIndex > 4) {
curColorIndex = 1;
}
SetCellColor(curColorIndex, dataGridView1.Rows[i 1].Cells[2]);
}
}
}
Walking through the method, we color the first cell before we enter the for
loop. Once in the for
loop we compare the current row cells value with the next rows cell value. If the values are equal, then we will use the same color. If the values are different, then we will change to the next color by incrementing curColorIndex
and then call the SetCellColor
for the second row. Then continue on to the next row. In the else
portion of the if
statement, we need to check and make sure curColorIndex
stays in bounds of the four (4) different colors. If the curColorIndex
gets greater than four (4), then we will simply set it back to 1 and repeat the same color scheme for the rest of the rows.
I hope this makes sense.