C# 如何强制 Panel1 和 Panel2 的 Paint 事件同时完成?
C# How to force Paint event of Panel1 and Panel2 complete at the same time?
我有一个 SplitContainer(确切地说是 NonFlickerSplitContainer 一个),我将它的两个面板视为一个单独的 canvas 来绘画。我使用 Graphics.DrawImage 方法分别在面板上绘制位图。我先刷新 Panel1,然后刷新 Panel2,这导致 vertical/horizontal 撕裂 - Panel1 的绘制结束,然后 Panel2 的绘制开始 - 这就是原因。我的问题的解决方案是什么?我将 splitContainer 用作具有 before/after 功能的 "bitmap video stream" 的输出。也许我可以冻结 UI 直到 Panel2_Paint 结束?
private void splitContainer_Panel1_Paint(object sender, PaintEventArgs e)
{
if (frameA != null)
{
if (ORIGINAL_SIZE_SET)
e.Graphics.DrawImage(frameA, 0, 0);
else
e.Graphics.DrawImage(frameA, 0, 0, ClientSize.Width, ClientSize.Height);
}
}
private void splitContainer_Panel2_Paint(object sender, PaintEventArgs e)
{
if (frameB != null)
{
//...
if (ORIGINAL_SIZE_SET)
e.Graphics.DrawImage(frameB, x, y);
else
e.Graphics.DrawImage(frameB, x, y, ClientSize.Width, ClientSize.Height);
}
}
private Bitmap frameA = null;
private Bitmap frameB = null;
private void RefreshOutput(bool refreshClipA = true, bool refreshClipB = true)
{
if (refreshClipA)
{
frameA = GetVideoFrame(...);
//...
}
if (refreshClipB)
{
frameB = GetVideoFrame(...);
//...
}
if (refreshClipA)
splitContainer.Panel1.Refresh();
if (refreshClipB)
splitContainer.Panel2.Refresh();
}
Maybe I can freeze UI somehow until Panel2_Paint ends?
看看:https://msdn.microsoft.com/en-us/library/system.windows.forms.control.suspendlayout(v=vs.110).aspx
在您的控件上调用 SuspendLayout(),执行所有图形操作,然后调用 ResumeLayout() 一次更新所有内容。该文档中有一个示例。
如果您的绘图操作花费的时间太长,那么临时图形工件可能会开始出现在 "frozen" 区域中,直到 ResumeLayout() 之后。
查看 SplitContainer.Invalidate(bool invalidate Children)
的文档。
来自link:
Invalidates a specific region of the control and causes a paint message to be sent to the control. Optionally, invalidates the child controls assigned to the control.
因此,与其分别使每个面板无效,不如调用此方法一次,它应该会执行您想要的操作。或者稍微修改一下代码:
if (refreshClipA && refreshClipB)
{
splitContainer.Invalidate(true);
}
else
{
if (refreshClipA)
{
splitContainer.Panel1.Refresh();
}
else if (refreshClipB)
{
splitContainer.Panel2.Refresh();
}
}
基本上我正在做的是,如果它们都需要重新粉刷,让 splitContainer
处理它,否则单独检查每一个并在需要时进行粉刷。
从@DonBoitnott 的评论开始,而不是使用 Invalidate(true)
使用 Refresh()
文档中的
Forces the control to invalidate its client area and immediately redraw itself and any child controls.
所以只需将 splitContainer.Invalidate(true)
更改为 splitContainer.Refresh()
。
我遇到过无法确保两个单独的 panel.Paint() 事件同时完成的情况,至少在 WinForms 项目中是这样。唯一对我有用的解决方案是 DonBoitnott 的建议。我现在使用单个面板并模拟 splitcontainer 行为。
If I were answering this, I would suggest you ditch the splitcontainer and render to a single surface, that way you are always in a single Paint event and you simply region it off and draw accordingly. – DonBoitnott Feb 17 '16 at 17:51
我有一个 SplitContainer(确切地说是 NonFlickerSplitContainer 一个),我将它的两个面板视为一个单独的 canvas 来绘画。我使用 Graphics.DrawImage 方法分别在面板上绘制位图。我先刷新 Panel1,然后刷新 Panel2,这导致 vertical/horizontal 撕裂 - Panel1 的绘制结束,然后 Panel2 的绘制开始 - 这就是原因。我的问题的解决方案是什么?我将 splitContainer 用作具有 before/after 功能的 "bitmap video stream" 的输出。也许我可以冻结 UI 直到 Panel2_Paint 结束?
private void splitContainer_Panel1_Paint(object sender, PaintEventArgs e)
{
if (frameA != null)
{
if (ORIGINAL_SIZE_SET)
e.Graphics.DrawImage(frameA, 0, 0);
else
e.Graphics.DrawImage(frameA, 0, 0, ClientSize.Width, ClientSize.Height);
}
}
private void splitContainer_Panel2_Paint(object sender, PaintEventArgs e)
{
if (frameB != null)
{
//...
if (ORIGINAL_SIZE_SET)
e.Graphics.DrawImage(frameB, x, y);
else
e.Graphics.DrawImage(frameB, x, y, ClientSize.Width, ClientSize.Height);
}
}
private Bitmap frameA = null;
private Bitmap frameB = null;
private void RefreshOutput(bool refreshClipA = true, bool refreshClipB = true)
{
if (refreshClipA)
{
frameA = GetVideoFrame(...);
//...
}
if (refreshClipB)
{
frameB = GetVideoFrame(...);
//...
}
if (refreshClipA)
splitContainer.Panel1.Refresh();
if (refreshClipB)
splitContainer.Panel2.Refresh();
}
Maybe I can freeze UI somehow until Panel2_Paint ends?
看看:https://msdn.microsoft.com/en-us/library/system.windows.forms.control.suspendlayout(v=vs.110).aspx
在您的控件上调用 SuspendLayout(),执行所有图形操作,然后调用 ResumeLayout() 一次更新所有内容。该文档中有一个示例。
如果您的绘图操作花费的时间太长,那么临时图形工件可能会开始出现在 "frozen" 区域中,直到 ResumeLayout() 之后。
查看 SplitContainer.Invalidate(bool invalidate Children)
的文档。
来自link:
Invalidates a specific region of the control and causes a paint message to be sent to the control. Optionally, invalidates the child controls assigned to the control.
因此,与其分别使每个面板无效,不如调用此方法一次,它应该会执行您想要的操作。或者稍微修改一下代码:
if (refreshClipA && refreshClipB)
{
splitContainer.Invalidate(true);
}
else
{
if (refreshClipA)
{
splitContainer.Panel1.Refresh();
}
else if (refreshClipB)
{
splitContainer.Panel2.Refresh();
}
}
基本上我正在做的是,如果它们都需要重新粉刷,让 splitContainer
处理它,否则单独检查每一个并在需要时进行粉刷。
从@DonBoitnott 的评论开始,而不是使用 Invalidate(true)
使用 Refresh()
文档中的
Forces the control to invalidate its client area and immediately redraw itself and any child controls.
所以只需将 splitContainer.Invalidate(true)
更改为 splitContainer.Refresh()
。
我遇到过无法确保两个单独的 panel.Paint() 事件同时完成的情况,至少在 WinForms 项目中是这样。唯一对我有用的解决方案是 DonBoitnott 的建议。我现在使用单个面板并模拟 splitcontainer 行为。
If I were answering this, I would suggest you ditch the splitcontainer and render to a single surface, that way you are always in a single Paint event and you simply region it off and draw accordingly. – DonBoitnott Feb 17 '16 at 17:51