在编译Any Cpu以及编译为x86时会发生这种情况。 GUI的各个部分不会重新绘制,除非它被调整大小,例如,如果主窗体最大化,某些控件不会随之调整大小,而其他部分的部分不会重绘并显示之前的内容。
这适用于32位机器,包括XP和Vista,但在64位Vista上(没有x64 XP可以测试)重绘只是不能正常工作。
任何人都有关于从何处开始跟踪此事的想法?
编辑:这发生在2台不同的机器上,至少我目前使用的是NVidia的最新驱动程序。
Edit2:在我的64位计算机上运行32位XP虚拟机,并且该应用程序没有在VM中显示重绘问题
Edit3:这可能是驱动程序问题,但我们不知道驱动程序是否或何时会解决问题。一位同事说家里的ATI卡比NVidia的问题要少,但过去几个月我一直在每月更新我的视频驱动程序而且还没有解决,所以我们不能只发布我们的产品并告诉我们的客户,有一天司机制造商可能会解决这个问题。
有没有人对要避免的事情有任何见解?我们正在编译为x86,所有组件都是x86。我似乎无法使用测试项目中的任何组件重现此问题,我还没有听到其他人在大多数组件论坛上报告这些问题,因此很可能这是我们正在做的事情。
答案 0 :(得分:14)
听起来非常像this问题。
在Windows上调整窗口大小时,您通常会得到一个链,其中每个窗口都会收到WM_SIZE
条消息,然后在其子级上调用MoveWindow()
(或类似),然后会收到WM_SIZE
和等等。我确信.NET在幕后做同样的事情。
在x64上,Windows限制了此嵌套的深度,在某个点(12-15个嵌套窗口)之后,它将不再发送WM_SIZE
个消息。 x86上似乎不存在此限制。此限制会影响在x64版本的Windows上运行的x86和x64代码。
这让我们玩了很多年,因为不同的x64安装会显示不同的症状。上面发布的MSDN博客有一些可能的解决方法 - 我们最终使用辅助线程异步地执行窗口大小,这很好地解决了问题。
答案 1 :(得分:3)
如果您使用的是Windows窗体,则可能与Windows 64位上的嵌套限制问题有关。
详细信息:http://www.feedghost.com/Blogs/BlogEntry.aspx?EntryId=17829
总结......
从MS源代码,在Control.SetBoundsCore中:
SafeNativeMethods.SetWindowPos(new HandleRef(window, Handle), NativeMethods.NullHandleRef, x, y, width, height, flags);
// NOTE: SetWindowPos causes a WM_WINDOWPOSCHANGED which is processed
// synchonously so we effectively end up in UpdateBounds immediately following
// SetWindowPos.
//
//UpdateBounds(x, y, width, height);
来自MSDN:
“一点调查显示Windows停止发送WM_SIZE 当它达到一定的嵌套时 水平。换句话说,它不会发送 如果你的话,WM_SIZE到您的子窗口 在处理时尝试调整它们的大小 父类中的WM_SIZE。根据 关于USER的东西/更新/服务 打包最大嵌套级别 它停止传播WM_SIZE可能会 从15到31甚至更多 更高(有效无法到达)下 最新的XP 32bit / sp2。
但是在XP x64下它仍然太少了,还有一些类似丑陋的东西 发生在某些情况下的其他消息 Vista的构建。
所以它肯定是Windows的错误。“
您有两种选择:要么降低控制层次结构的深度(更理想的解决方案),要么从您使用的每个系统控件中派生“固定”控件,如下所示:
public class FixedPanel : Panel
{
protected override void SetBoundsCore( int x, int y, int width, int height, BoundsSpecified specified )
{
base.SetBoundsCore( x, y, width, height, specified );
if( specified != BoundsSpecified.None )
{
if( ( specified & BoundsSpecified.X ) == BoundsSpecified.None )
{
x = Left;
}
if( ( specified & BoundsSpecified.Y ) == BoundsSpecified.None )
{
y = Top;
}
if( ( specified & BoundsSpecified.Width ) == BoundsSpecified.None )
{
width = Width;
}
if( ( specified & BoundsSpecified.Height ) == BoundsSpecified.None )
{
height = Height;
}
}
if( x != Left || y != Top || width != Width || height != Height )
{
UpdateBounds( x, y, width, height );
}
}
}
答案 2 :(得分:1)
我认为此问题的最可能原因是您的应用程序中的重绘问题。在64位上有一个微妙的Windows消息排序差异可能会在您的代码中暴露此问题。
您可以通过执行以下操作来试验此操作。
我会将计时器设置为长达5秒的时间。然后在Win64上运行该应用程序,看看是否能解决问题。如果是这样,那么最可能的原因是你的一个控件没有正确地表明它已被无效。
我会从应用程序中的任何自定义控件开始。系统地向代码中的每个重写方法和事件处理程序添加Update调用。最终你会找到解决问题的那个,然后你就会知道bug究竟在哪里。
答案 3 :(得分:1)
如果您使用MSDN上blog中描述的BeginInvoke()解决方案,请确保禁用覆盖OnSizeChanged()的控件的子对接。我有Dock = DockStyle.Fill并且必须更改为DockStyle.None才能使修复工作。
答案 4 :(得分:0)
听起来像显示器驱动程序问题...
尝试更新到最新的驱动程序,看看是否能解决问题? 64/32位差异可能是红鲱鱼......
答案 5 :(得分:0)
我同意戈登的观点。我已经看到全新的64位机器出现问题的问题,程序在32位下看起来很好,但在64位机器上会出现奇怪的问题。更新到最新/推荐的驱动程序几乎总是解决问题。
答案 6 :(得分:0)
您可以在没有问题的情况下在虚拟操作系统上运行该程序,这表明它是一个驱动程序问题,因为(至少在VirtualPC中)图形卡是模拟的。这意味着图形卡通常会处理的一些事情现在由CPU完成,因此不与图形驱动程序交互。请注意,我不是虚拟化方面的专家,我认为虚拟化层可能会以其他方式影响该问题。
答案 7 :(得分:0)
我认为这与树中嵌套的HWND的数量有关。我不知道具体的细节,但是对64bit的嵌套HWND有一些限制。我看到它发生的时间,我通过从完整的vista基本(或航空)主题回退到Windows经典来解决它。此时问题就消失了。
尝试切换到classic,如果解决了,请查看是否可以减少嵌套的HWND数量。