Bug 还是我做错了什么?用户控制绘画

发布于 2024-11-07 22:28:31 字数 582 浏览 2 评论 0原文

private void UserControl1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.DrawEllipse(Pens.Black, new Rectangle(-200, -500, this.Width + 400, this.Height + 420));
}

将以上代码粘贴到用户控件中。将用户控件拖放到窗体上并将其锚定到所有 4 个点。

在设计器中(在 Visual Studio 2010 下)它可以完美呈现(即使您调整大小)。运行它并尝试调整表单大小,椭圆变得倾斜。

以下是两个示例,都是在调整大小之后,第一个是运行时的,第二个是在设计器中的。

调整大小后运行 Designer After Resize

显然设计器中的行为不能总是假设是相同的(尽管这会很好)但我的理解是上面的代码是完全合法的。我错了吗?

private void UserControl1_Paint(object sender, PaintEventArgs e)
{
    e.Graphics.DrawEllipse(Pens.Black, new Rectangle(-200, -500, this.Width + 400, this.Height + 420));
}

Paste the above code into a usercontrol. Drop the usercontrol onto a form and anchor it to all 4 points.

In the designer (Under Visual Studio 2010) it renders perfectly (even as you resize). Run it and try and resize the form and the ellipse becomes skewed.

Here are two examples both after resizes the first while running, the second in the designer.

Running After Resize
Designer After Resize

Obviously the behavior in the designer can't always be assumed to be the same (Although it would be nice) but my understanding is that the code above is completely legal. Am I wrong?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

影子的影子 2024-11-14 22:28:31

Stecya 已发布“修复” ”,但省略了详细说明为什么有效或为什么您会看到设计器中的行为与实际中的行为之间存在差异的解释正在运行的应用程序。在我看来,这使得答案的用处很小,所以我想我应该尝试做出解释。

您已经知道调用 Invalidate 方法 是解决方案。它的作用是告诉 Windows 下次绘制窗口时需要重新绘制控件的整个表面区域。很简单,但为什么不必在设计器中执行此操作呢?

答案在于您正在运行启用了 Windows Aero 主题的程序。 Aero 使用一个全新的窗口管理器,称为桌面窗口管理器(或简称 DWM),基于作品。每个窗口都是双缓冲的,这意味着它的图形在屏幕外渲染为临时位图,然后才传输到屏幕。这允许当今用户似乎喜欢的各种酷炫效果和奇特的过渡。

但是,当然,这意味着已经绘制的部分不会被删除和重新绘制,除非您明确指示 Windows 需要这样做。这对于设计器内部的表单来说不是问题,因为在那里,Aero 的 DWM 合成未启用。当窗口大小调整时,它会自动重新绘制,并且您的旋风看起来平滑且正确。

在设计器之外,启用 Aero 合成后,只有控件的新暴露部分会被重绘(其余部分仍然在缓冲区中),因此形状是错误的。旧形状的一部分仍然存在,新形状的一部分刚刚被绘制。调用 Invalidate 告诉 Windows“此控件的图形表面已更改;忘记您认为了解的所有内容并下次从头开始重新绘制”。因此,Windows 尽职尽责地服从,从屏幕外缓冲区中丢弃该部分,并从头开始重新绘制它,从而生成正确渲染的、平滑的路径。

您可以用另一种更优雅的方式实现相同的更改:告诉控件它需要在每次调整大小时重新绘制自己。将以下代码插入到控件的构造函数中:

public MyUserControl()
{
    // Force the control to redraw itself each time it is resized
    this.SetStyle(ControlStyles.ResizeRedraw);
}

Stecya has posted the "fix", but omitted an explanation detailing why that works or why you're seeing a discrepancy between the behavior in the designer and in the running application. In my mind, that makes the answer only minimally useful, so I thought I'd weigh in with an attempt at an explanation.

You already know that calling the Invalidate method is the solution. What this does is tell Windows that the entire surface area of the control needs to be redrawn the next time the window gets painted. Simple enough, but why don't you have to do this in the designer?

The answer lies in the fact that you're running the program with the Windows Aero theme enabled. Aero uses an entirely new window manager called the Desktop Window Manager (or DWM for short) based on composition. Each window is double-buffered, meaning that its graphics are rendered off-screen into a temporary bitmap, and only then blitted to the screen. This allows all sorts of cool effects and fancy transitions that users seem to like nowadays.

But, of course, it means that the sections that have already been drawn aren't erased and redrawn unless you explicitly instruct Windows that it needs to do so. That's not a problem for the form inside the designer, because there, Aero's DWM composition is not enabled. When the window gets resized, it is automatically redrawn, and your swoosh looks smooth and correct.

Outside of the designer, with Aero composition enabled, only the newly-exposed portions of your control are redrawn (the rest are still there in the buffer), so the shape is wrong. Part of the old shape is still there, and part of the new shape was just drawn in. Calling Invalidate tells Windows "the graphic surface of this control has changed; forget everything you thought you knew about it and redraw it from scratch next time". So Windows dutifully obeys, discarding that portion from its off-screen buffer and redraws it in from scratch, producing a correctly-rendered, nicely-smoothed path.

You can effect the same change in another somewhat more elegant way: Tell the control that it needs to redraw itself every time that it is resized. Insert the following code into the control's constructor method:

public MyUserControl()
{
    // Force the control to redraw itself each time it is resized
    this.SetStyle(ControlStyles.ResizeRedraw);
}
离不开的别离 2024-11-14 22:28:31

您可以在调整大小时手动使控件无效

private void Form1_Resize(object sender, EventArgs e)
{
    userControl11.Invalidate();
}

You can manually Invalidate control while resizing

private void Form1_Resize(object sender, EventArgs e)
{
    userControl11.Invalidate();
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文