想象以下场景:
this.SetStyle(ControlStyles.UserPaint, true); //this doesn’t change anything
…
void OpenSomeForm()
{
SomeForm sf = new SomeForm();
sf.SomeEvent += new … (SomeEventOcurred);
sf.ShowDialog();
}
private void SomeEventOcurred(…)
{
OnePanelInThisForm.Invalidate();
}
private void OnePanelInThisForm_Paint(object sender, PaintEventArgs e)
{
DoSomeDrawing(e.Graphics);
}
现在,OnePanelInThisForm 在表单加载时正确绘制。但如果 SomeEventOcurred 是从“SomeForm”触发的,则不会触发绘制事件。如果我关闭并重新打开表单,它会正确重绘。如果我在执行的表单中添加一个按钮: OnePanelInThisForm.Invalidate(); 面板正确重绘。
我错过了什么?
更新:澄清。(我们为什么不首先这样做……)
我有一个 FORM_A。这个 FORM_A 有一个面板,它覆盖了 Paint 事件。这是一个标准的 WinForm。在 Paint 中它画了一个圆圈。这行得通。原来 FORM_A 有一个打开 FORM_B 的按钮。但在此之前,它订阅了 FORM_B 中的一个自定义事件,称为:SomeEvent。(参见上面的示例)。所以 FORM_B 可以告诉 FORM_A 关于“SomeEvent”。
现在,FORM_B 也是一个普通的 WinForm。它有一个普通的按钮。在该按钮的 Click 事件中,它会打开 FORM_C。FORM_C 也有一个名为 SomeEvent 的事件,显然 FORM_B 订阅了该事件。和以前一模一样。这个想法是 FORM_C 有一个按钮可以触发该事件,通知感兴趣的订阅者。在这种情况下,当 FORM_C 触发事件时,FORM_B 被订阅并感兴趣。
当 FORM_B 收到回调时,它唯一要做的就是……通知相关方(在本例中为 FORM A)该事件已被触发。
现在,即使 Form C 仍然是顶层表单,调用堆栈也会返回到 FormA,返回到定义为第一个事件的回调的方法。
此代码执行。它所做的只是 somePanel.Invalidate()(或 Refresh(),结果相同)。
该面板的 PAINT 方法中的断点表明代码没有被调用。尽管无效,但没有引发 Paint 事件。我认为发生这种情况是因为表单(以及面板)实际上被 FORMB 和 FORMC(仍然打开)覆盖。
就这样。如果我关闭表格 C 然后关闭表格 B,表格 A 仍然不会引发绘制事件。我已经尝试使表单激活面板无效,但这并没有发生。
如果我关闭表单 A 并重新打开它,那么绘图当然是正确的。
希望这能让它更清楚。
代码并不多,因为这很简单,FORM A > B > C(火灾事件)-> B -> A -> Invalidate()。