Good day!
I have read a lot about dynamic cells back color changing, but have not found the resolve of my problem.
In my project, I used 32x32 DataGridView. All values are integer, also I've changed default cell format to Numeric.
This code makes gradient painting without any problem:
void AFRTableGraient()
{
for (int i = 0; i < dataGridViewTAF.ColumnCount; i++)
{
for (int j = 0; j < dataGridViewTAF.RowCount; j++)
{
try
{
if (dataGridViewTAF.Rows[i].Cells[j].Value == null)
{
break;
}
dataGridViewTAF.Rows[i].Cells[j].Style.BackColor = Color.FromArgb(0x10 + (int)dataGridViewTAF.Rows[i].Cells[j].Value, 0x88 + (int)dataGridViewTAF.Rows[i].Cells[j].Value, 0x88 + (int)dataGridViewTAF.Rows[i].Cells[j].Value);
}
catch
{
break;
}
}
}
dataGridViewTAF.Update();
dataGridViewTAF.Refresh();
}
But I need to change cell color after value changed.
I've used CellFormatting, KeyDown, CellLeave, CellPainting, Enter, etc, events, but has no result.
When I tried to use CellPainting method, the app is freeze, but update the color is not happening.
Also, I've tried to use the "timer", but still nothing.
I know, there is a simple way of resolving, but I need help to found it.
Thanks!
Related
I have a RichTextBox. I'm trying to code so that if a specific color is found in the SelectionBackColor property of the RTB, the background color of the words/ texts to be removed. For that, I need to detect if there exists multiple colors in the RTB. However, according to the documentation,
If the current text selection has more than one color specified, this property returns Color.Empty.
This is what I've tried so far:
private void randomBtn_Click(object sender, EventArgs e)
{
int startIndex = 0; //start from beginning of the richTextBox1
int endIndex = this.richTextBox1.TextLength; //until the end of all text available
this.richTextBox1.Select(startIndex, endIndex); //select from start until the end
if(endIndex != 0)
{
for(int i=startIndex; i< endIndex; i++)
{
if (this.richTextBox1.Text[i].ToString().Contains(" ")) //skips white spaces
{
continue;
}
else
{
while ((this.richTextBox1.BackColor != Color.Empty))
{
if (this.richTextBox1.SelectionBackColor.R == 155 && this.richTextBox1.SelectionBackColor.G == 255 && this.richTextBox1.SelectionBackColor.B == 255)
{
this.richTextBox1.HideSelection = true; //to prevent text highlighted
MessageBox.Show(this, "Texts with RGB(155, 255, 255) found!", "", MessageBoxButtons.OK);
break;
}
else
{
this.richTextBox1.HideSelection = true;
MessageBox.Show(this, "Error!", "", MessageBoxButtons.OK);
break;
}
}
}
}
}
else
{
MessageBox.Show(this, "richTextBox1 is empty!", "Alert!", MessageBoxButtons.OK);
}
}
To test, I added a breakpoint at the code containing the while line. Below shows the success and fail criterion,
The code works if:
There is no whitespace(at all)
There is only one color in the RTB
The code fails if:
There are whitespaces in between texts/ words/ characters
There are multiple colors in the RTB
Below shows the program execution examples:
This is when only one color is applied in the RTB(success),
This is when only one color and a whitespace are applied in the RTB(fail),
This is when multiple colors and whitespaces are applied in the RTB(fail),
So, is there any ways to override the return value of the SelectionColor property to be able to detect multiple colors, or are there any other ways of doing this? Just so you know, I've searched for this kind of problem over the internet, but I didn't think I've find any related issues.
It took me a while to figure out what #TaW meant in the comment section, but thanks to him, I've managed to solve this issue.
Actually, based on my reply in the comment section that I asked #TaW, what I thought as the same concept, was actually wrong. In the post above, what I did was entirely wrong:
I was supposed to assess each text one by one to know what their colors are. However, the codes below were already wrong to begin with.:
int startIndex = 0;
int endIndex = this.richTextBox1.TextLength;
this.richTextBox1.Select(startIndex, endIndex);
To analyze how RTB.SelectionColor, RTB.SelectionStart, and RTB.SelectionLength work, I decided to create another project. The project is a simple program containing an RTB, and some other buttons to manage the RTB's SelectionColor. If you want to check for the project that I've done, you're always welcomed to visit this link.
From "2", I re-used all the codes to suit the original project that I was working on. Now, it's all fine and working as it should.
To note, there are two important concepts/ ideas on managing the Selection property of the RTB.
If you are concerned of assessing each and every text in the RTB, you should code it like this:
private void methodA(RichTextBox localRTB)
{
//go through text one by one
int startIndex = 0;
int endIndex = localRTB.TextLength;
localRTB.SelectionStart = startIndex;
localRTB.SelectionLength = 1; //always 1 'cuz we want to assess each text one by one
while (localRTB.SelectionStart < endIndex)
{
//if the SelectionBackColor is red, change it to white
if (localRTB.SelectionBackColor == Color.Red) //take red color for example
{
localRTB.SelectionBackColor = Color.White;
}
//--manage bg color of selected text in RTB--
//so that able to go to next text
localRTB.SelectionStart += 1;
}
//finally...
localRTB.DeselectAll(); //unselect text in RTB
localRTB.Select(); //set focus back to the RTB
}
Below shows the result of the codes above(1):
If you don't really care about assessing each and every text in the RTB, you should code it like this instead:
private void methodB(RichTextBox localRTB)
{
int startIndex;
int endIndex;
if (localRTB.SelectionLength.Equals(0)) //if user don't select any text
{
startIndex = 0; //from beginning of RTB
endIndex = localRTB.TextLength; //'til the end of RTB
//--manage selected text in the RTB--
localRTB.SelectionStart = startIndex;
localRTB.SelectionLength = endIndex;
localRTB.Select(localRTB.SelectionStart, localRTB.SelectionLength);
//--manage selected text in the RTB--
}
else if (!(localRTB.SelectionLength.Equals(0))) //if user has text selected
{
startIndex = localRTB.SelectionStart; //from beginning of RTB
endIndex = localRTB.SelectionLength; //'til the end of RTB
if (localRTB.SelectedText.Contains(" ")) //skips whitespaces if selected together with text
{
if (localRTB.SelectedText.EndsWith(" "))
{
endIndex -= 1;
}
}
//--manage selected text in the RTB--
localRTB.Select(startIndex, endIndex);
//--manage selected text in the RTB--
}
}
Below shows the result of the codes above(2):
Peace...✌️
I've been working on drawing a grid in C#, which works! But somehow I keep running into some problems with the method DrawGrid.
I found that it is being redrawn every time a label gets added, and continuously after that. Here is my code:
Rectangle[,] rec = new Rectangle[6,6];
Label label_1 = new Label();
Label label_2 = new Label();
public Reversi()
{
ClientSize = new Size(500,425);
BackColor = Color.DarkGreen;
NewGame();
Paint += DrawGrid;
}
public void NewGame()
{
// here is some more stuff which I will leave out for the sake of clarity
for (int i = 0; i < grspel; i++)
{
for (int j = 0; j < grspel; j++)
{
rec[i, j] = new Rectangle(50 + i * 50, 100 + j * 50, 50, 50);
}
}
DrawLabels();
}
public void DrawLabels()
{
label_1.Location = new Point(20, 50);
label_1.Text = "Zwart: " + zwart;
Controls.Add(label_1);
label_2.Location = new Point(330, 50);
label_2.Text = "Wit: " + wit;
Controls.Add(label_2);
}
public void DrawGrid(object o, PaintEventArgs pea)
{
MessageBox.Show("test");
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 6; j++)
{
pea.Graphics.DrawRectangle(new Pen(Brushes.Black), rec[i,j]);
}
}
}
To visualize my problem I placed MessageBox.Show("test"); at the start of my DrawGrid method. The rest of my code (which is not on here) uses this method and is not working properly. I've narrowed the problem down to this.
Getting rid of the Controls.Add(label_i) fixes the problem, but I need the labels.
Why does this happen and more importantly, how can I fix it?
You add a label, thus there's an event that UI changes and needs to repaint. It should paint the added label, right? IMHO that's expected.
You don't need to add the labels to the list of controls each time. Just add them once (e.g. in Form.Load).
However, changing the position of the label will likely also require a repaint. It should paint the label at the new position, right? But your position is constant as well. Just set the position once.
Repainting is normal and good, because it keeps the contents updated. It shouldn't be a problem. So, why don't you like it? Probably it causes flickering and you don't like that.
Showing a MessageBox might not be a good idea either. If the MessageBox is in front of your form, the part that is behind the MessageBox will need to be painted again.
You can
use SuspendLayout() to tell the painter that it's not worth reacting to changes immediately, but wait until you finished making all layout related changes. Use ResumeLayout() to tell the painter it's time to paint now.
check out options for double buffering
but I need the labels
Actually you don't. You can use Graphics.DrawString() instead of using a label.
my code seems to be not working
gridView6.Columns["QueueID"].OptionsColumn.AllowEdit = true;
I also tried
int n = Convert.ToInt32(gridView6.Columns.Count.ToString());
for (int i = 0; i < n; i++)
{
gridView6.Columns["QueueID"].OptionsColumn.AllowEdit = true;
}
I have tried these codes but my gridview still does not allow editing after executing my winform, Is there other way to make this work? because my code does not catch any errors
AllowEdit is in effect if the View's ColumnView.Editable property is set to true.
Check if you enabled ColumnViewOptionsBehavior.Editable Property.
I have added buttons to a grid layout I created. Here is the code for that.
int nodeIndex = 0;
for (i = 0; i < usedRows; i++)
{
for (j = 0; j < cols; j++)
{
this.tableLayoutPanel1.Controls.Add(nodes[nodeIndex++], j, i);
}
}
Later on in the application I want to be able to change the color of a button at a specified position. Basically change the back round color of the button at position i,j. How would I get access to that specific button? I am using winforms. Is there something like
button = this.tableLayoutPanel1.Controls.GetChildAtPosition(j, i)
You can use something along these lines.
button = this.tableLayoutPanel1.GetControlFromPosition(j, i);
button.BackColor = Color.BLACK;
So first you want to able to find the control and conveniently there is a method called FindControl() that can do just that
MSDN link for reference: http://msdn.microsoft.com/en-us/library/system.web.ui.control.findcontrol(v=vs.110).aspx
Second you want to be able to change the color of the button once you find it.
For buttons you probably want to use the BackColor property.
Again MSDN link for reference:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.backcolor(v=vs.110).aspx
The trick is going to be finding the control and then working with that control as an object to change the color. Don't forget that you can cast the control to a button type once you find it, which should give you access to the BackColor property.
For scrolling the datagrid, I use following code:
dataGridView1.FirstDisplayedScrollingRowIndex = currentRowIndexInGridView;
dataGridView1.Update();
That works fine for rows not at the bottom of the grid.
If I use it for bottom rows, the setter doesnt set it to the value I wanted, when I inspect it during debugging.
E.g. I am setting FirstDisplayedScrollingRowIndex= 103, but after the assignment FirstDisplayedScrollingRowIndex has the value 90 and hence the desired row is not visible.
From a certain point it stops scrolling and I cant see the last 5 rows.
If I am adding new rows and setting them to be displayed, it scrolls by one, but I dont see the last 5 rows again.
I think it has something to do with the fact, the some of my rows have different height and some internal estiment of DisplayedRowCount fails ???
Is there a way of detecting this situation and then forcing scrolling to the bottom of the datagrid?
EDIT:
The important part of the FirstDisplayedScrollingRowIndex setter looks like this in the Reflector:
if (value > this.displayedBandsInfo.FirstDisplayedScrollingRow)
{
int rows = this.Rows.GetRowCount(DataGridViewElementStates.Visible, this.displayedBandsInfo.FirstDisplayedScrollingRow, value);
this.ScrollRowsByCount(rows, (rows > 1) ? ScrollEventType.LargeIncrement : ScrollEventType.SmallIncrement);
}
else
{
this.ScrollRowIntoView(-1, value, true, false);
}
There seems to be an error in computing the rows variable.
Call following method whenever a new row is added
private void Autoscroll()
{
if (dgv.FirstDisplayedScrollingRowIndex + dgv.DisplayedRowCount(false) < dgv.Rows.Count)
{
dgv.FirstDisplayedScrollingRowIndex += dgv.DisplayedRowCount(false);
}
else
{
dgv.FirstDisplayedScrollingRowIndex = dgv.Rows.Count - 1;
}
}
I had to force all the rows to have the same width, otherwise the
FirstDisplayedScrollingRowIndex
setter is buggy.
I have similar issue but I found how to solved.
The problem seams to be that DataGridView required windows form refresh and only after that can be set FirstDisplayedScrollingRowIndex to the new index.
What I did?
Timer refreshTimer = new Timer();
public void RefreshLog()
{
dataGridViewVesselLog.DataSource = Log.Items;
dataGridViewVesselLog.Update();
dataGridViewVesselLog.Refresh();
refreshTimer.Interval = 100;
refreshTimer.Tick += (s, e) =>
{
if (dataGridViewVesselLog.Rows.Count > 0)
{
foreach (DataGridViewRow r in dataGridViewVesselLog.SelectedRows)
r.Selected = false;
dataGridViewVesselLog.Rows[dataGridViewVesselLog.Rows.Count - 1].Selected = true;
dataGridViewVesselLog.FirstDisplayedScrollingRowIndex = (int)(dataGridViewVesselLog.Rows.Count - 1);
}
refreshTimer.Stop();
}
refreshTimer.Start();
}