为什么我 运行 在 TextChanged 事件中使用相同的代码而不是在 Button Click 中得到不同的结果?
Why do I get different results when I run the same code in a TextChanged event as opposed to a Button Click?
我有一个循环访问 Datagridview 并找到与提供的搜索查询匹配的函数。
它使用找到的 "hits" 在 datagridview 的右侧绘制一个面板,显示命中相对于滚动条的位置。
当我 运行 在按钮单击事件中使用此代码时,它按预期工作。
当我在一个文本更改事件中 运行 它时,代码 运行 如预期的那样,然后面板自行清除。
这只会在每个调试会话的代码第一次 运行 时发生。会话的其余部分,文本更改事件工作正常,面板保留其应有的绘制部分。
最初,出于开发目的,我将代码直接放在按钮事件处理程序中。只有当我在文本更改事件中放置相同的代码时,我才第一次看到这个问题。
我已经将代码放入其自己的函数中,在按钮单击和文本更改事件中调用它。
所以看起来像这样:
private void btnSearch_Click(object sender, EventArgs e)
{
Search();
}
private void TbSearch_TextChanged(object sender, EventArgs e)
{
Search();
}
"Search" 包含:
private void Search()
{
PanelClear();
if (tbSearch.Text.Length > 2)
{
Searchy(tbSearch.Text);
if (_hits.Count > 0)
{
foreach (var hit in _hits){PanelPaint_paint(hit);}
}
}
}
PanelClear
包含:
private void PanelClear()
{
//Clears the list of matches.
_hits.Clear();
//Invalidates my panel control.
panelPaint.Invalidate();
//Hides a textbox
tbTotal.Visible = false;
}
和PanelPaint_paint
:
private void PanelPaint_paint(Hit hit)
{
Graphics g = panelPaint.CreateGraphics();
Color xx = ext.myColor;
Color saved = hit.color;
if (saved != Color.Empty) xx = hit.color;
Pen myPen = new Pen(xx) { Width = 1 };
int dgvl = dgvEvents.Rows.Count;
int pnll = panelPaint.Height;
int hitl = hit.RowNum;
double percent = ((double)hitl / (double)dgvl) * pnll;
float x = (float)percent;
g.DrawLine(myPen, 1, x, panelPaint.Width, x);
dgvEvents.Rows[hit.RowNum].Cells[2].Style = new DataGridViewCellStyle
{
BackColor = xx,
ForeColor = invert(xx)
};
extrabuttons(true);
tbTotal.Text = allhits().Count.ToString();
}
所以这是一个 gif,显示当我 运行 在一个简单的按钮中单击搜索时会发生什么:
Panel Paint on Button Click event
您会注意到,我点击了按钮,面板保留了它的颜色。
如果我将相同的代码放入 TextChanged 事件处理程序中,会发生以下情况:
Panel Paint on TextChanged event
它在搜索到 3 个字符之前不会进行搜索,所以您会看到,一旦我输入 'U',它就会 运行 进行搜索,绘制面板,但随后立即将其清除。所有其他搜索,例如当我添加 'E' 或退格回 'U' 时都可以正常工作。
当您以这种方式创建 Graphics 对象时:
Graphics g = panelPaint.CreateGraphics();
您使用此对象绘制的内容将不会保留。控件每次重绘(无效)时都会生成一个新的 Graphics 对象。这种情况经常发生。这意味着每次 Control 无效时都需要使用 Paint
事件的 PaintEventArgs 提供的当前 Graphics 对象刷新绘图。 (您会经常在 MSDN 文档和 Whosebug 中的许多问题中找到此建议)。
因此,您总是在 Paint
处理程序(或覆盖的 OnPaint 方法)中执行所有绘制。
不同的事件可能会导致控件失效(重新绘制):当表单为 minimized/maximized 时,当另一个 object/Window 移动到它上面时,当系统广播设置更改消息时(和其他)和许多其他条件。
此外,当表单的 AutoValidate 功能触发时:
Gets or sets a value that indicates whether controls in this container
will be automatically validated when the focus changes.
尝试修改代码如下。请注意,我无法测试此代码,因为我没有此处使用的对象和某些值。我希望这可以帮助你调整你的代码。
private void Search() {
_hits.Clear();
tbTotal.Visible = false;
if (tbSearch.Text.Length < 3) return;
Searchy(tbSearch.Text);
if (_hits.Count == 0) return;
foreach (var hit in _hits) {
dgvEvents.Rows[hit.RowNum].Cells[2].Style = new DataGridViewCellStyle {
BackColor = hit.color == Color.Empty ? ext.myColor : hit.color,
ForeColor = invert(BackColor)
};
}
panelPaint.Invalidate();
extrabuttons(true);
tbTotal.Text = allhits().Count.ToString();
}
private void panelPaint_Paint(object sender, PaintEventArgs e)
{
if (_hits.Count == 0) return;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
foreach (var hit in _hits) {
PaintPanel(hit, e.Graphics);
}
}
private void PaintPanel(Hit hit, Graphics g)
{
using (Pen myPen = new Pen(hit.color == Color.Empty ? ext.myColor : hit.color, 1)) {
float percent = ((float)hit.RowNum / dgvEvents.Rows.Count) * (float)panelPaint.Height;
g.DrawLine(myPen, 1, percent, panelPaint.Width, percent);
}
}
我有一个循环访问 Datagridview 并找到与提供的搜索查询匹配的函数。 它使用找到的 "hits" 在 datagridview 的右侧绘制一个面板,显示命中相对于滚动条的位置。
当我 运行 在按钮单击事件中使用此代码时,它按预期工作。 当我在一个文本更改事件中 运行 它时,代码 运行 如预期的那样,然后面板自行清除。
这只会在每个调试会话的代码第一次 运行 时发生。会话的其余部分,文本更改事件工作正常,面板保留其应有的绘制部分。
最初,出于开发目的,我将代码直接放在按钮事件处理程序中。只有当我在文本更改事件中放置相同的代码时,我才第一次看到这个问题。
我已经将代码放入其自己的函数中,在按钮单击和文本更改事件中调用它。
所以看起来像这样:
private void btnSearch_Click(object sender, EventArgs e)
{
Search();
}
private void TbSearch_TextChanged(object sender, EventArgs e)
{
Search();
}
"Search" 包含:
private void Search()
{
PanelClear();
if (tbSearch.Text.Length > 2)
{
Searchy(tbSearch.Text);
if (_hits.Count > 0)
{
foreach (var hit in _hits){PanelPaint_paint(hit);}
}
}
}
PanelClear
包含:
private void PanelClear()
{
//Clears the list of matches.
_hits.Clear();
//Invalidates my panel control.
panelPaint.Invalidate();
//Hides a textbox
tbTotal.Visible = false;
}
和PanelPaint_paint
:
private void PanelPaint_paint(Hit hit)
{
Graphics g = panelPaint.CreateGraphics();
Color xx = ext.myColor;
Color saved = hit.color;
if (saved != Color.Empty) xx = hit.color;
Pen myPen = new Pen(xx) { Width = 1 };
int dgvl = dgvEvents.Rows.Count;
int pnll = panelPaint.Height;
int hitl = hit.RowNum;
double percent = ((double)hitl / (double)dgvl) * pnll;
float x = (float)percent;
g.DrawLine(myPen, 1, x, panelPaint.Width, x);
dgvEvents.Rows[hit.RowNum].Cells[2].Style = new DataGridViewCellStyle
{
BackColor = xx,
ForeColor = invert(xx)
};
extrabuttons(true);
tbTotal.Text = allhits().Count.ToString();
}
所以这是一个 gif,显示当我 运行 在一个简单的按钮中单击搜索时会发生什么:
Panel Paint on Button Click event
您会注意到,我点击了按钮,面板保留了它的颜色。
如果我将相同的代码放入 TextChanged 事件处理程序中,会发生以下情况:
Panel Paint on TextChanged event
它在搜索到 3 个字符之前不会进行搜索,所以您会看到,一旦我输入 'U',它就会 运行 进行搜索,绘制面板,但随后立即将其清除。所有其他搜索,例如当我添加 'E' 或退格回 'U' 时都可以正常工作。
当您以这种方式创建 Graphics 对象时:
Graphics g = panelPaint.CreateGraphics();
您使用此对象绘制的内容将不会保留。控件每次重绘(无效)时都会生成一个新的 Graphics 对象。这种情况经常发生。这意味着每次 Control 无效时都需要使用 Paint
事件的 PaintEventArgs 提供的当前 Graphics 对象刷新绘图。 (您会经常在 MSDN 文档和 Whosebug 中的许多问题中找到此建议)。
因此,您总是在 Paint
处理程序(或覆盖的 OnPaint 方法)中执行所有绘制。
不同的事件可能会导致控件失效(重新绘制):当表单为 minimized/maximized 时,当另一个 object/Window 移动到它上面时,当系统广播设置更改消息时(和其他)和许多其他条件。
此外,当表单的 AutoValidate 功能触发时:
Gets or sets a value that indicates whether controls in this container will be automatically validated when the focus changes.
尝试修改代码如下。请注意,我无法测试此代码,因为我没有此处使用的对象和某些值。我希望这可以帮助你调整你的代码。
private void Search() {
_hits.Clear();
tbTotal.Visible = false;
if (tbSearch.Text.Length < 3) return;
Searchy(tbSearch.Text);
if (_hits.Count == 0) return;
foreach (var hit in _hits) {
dgvEvents.Rows[hit.RowNum].Cells[2].Style = new DataGridViewCellStyle {
BackColor = hit.color == Color.Empty ? ext.myColor : hit.color,
ForeColor = invert(BackColor)
};
}
panelPaint.Invalidate();
extrabuttons(true);
tbTotal.Text = allhits().Count.ToString();
}
private void panelPaint_Paint(object sender, PaintEventArgs e)
{
if (_hits.Count == 0) return;
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
foreach (var hit in _hits) {
PaintPanel(hit, e.Graphics);
}
}
private void PaintPanel(Hit hit, Graphics g)
{
using (Pen myPen = new Pen(hit.color == Color.Empty ? ext.myColor : hit.color, 1)) {
float percent = ((float)hit.RowNum / dgvEvents.Rows.Count) * (float)panelPaint.Height;
g.DrawLine(myPen, 1, percent, panelPaint.Width, percent);
}
}