2012-07-17 77 views
3
ControlHelper.SuspendDrawing(panel); 
panel.Controls.Clear(); 
AddItemIdLabel(); 
AddLastEditedLabel(); 
AddDeleteButton(); 
AddSaveButton(); 
ControlHelper.ResumeDrawing(panel); 

public static class ControlHelper 
{ 
    [DllImport("user32.dll")] 
    private static extern int SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam); 

    private const int WM_SETREDRAW = 0xB; 

    public static void SuspendDrawing(Control target) 
    { 
     SendMessage(target.Handle, WM_SETREDRAW, 0, 0); 
    } 

    public static void ResumeDrawing(Control target) 
    { 
     SendMessage(target.Handle, WM_SETREDRAW, 1, 0); 
     target.Refresh(); 
    } 
} 

如果使用上面的代码进行测试,面板的某些部分未被刷新。 您可以在没有添加新控件的地方看到Clear()之前的旧控件。将WM_SETREDRAW消息发送到面板后刷新

如果我把panel.Controls.Clear();ControlHelper.SuspendDrawing(panel);一切正常intented 一些闪烁是可见的,我正在努力避免的。

那么这里发生了什么?如何根据我在暂停之前还是之后清除控制集合有所作为?

回答

0

您的target.Refresh()调用并未完全使旧控件被删除的区域无效。由于Control.Refresh()是一种“虚拟”方法,因此可能会被覆盖,并可能会产生这样的副作用。

为保证完全覆盖,您应该在ResumeDrawing()内使用Invalidate(true) & Update()方法。 Invalidate(true)方法会将控件的整个区域和所有子控件设置为无效,并且Update()方法将在最后重新绘制所有内容。

另外,您应该考虑将这些方法作为.NET扩展实现。 这将在SuspendDrawing()ResumeDrawing()方法自动添加到每个System.Windows.Forms.Control的,你有一个在其中扩展声明的命名空间中:

[DllImport("user32.dll")] 
public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam); 
private const int WM_SETREDRAW = 11; 

public static void SuspendDrawing(this Control Target) 
{ 
    SendMessage(Target.Handle, WM_SETREDRAW, false, 0); 
} 

public static void ResumeDrawing(this Control Target) 
{ 
    SendMessage(Target.Handle, WM_SETREDRAW, true, 0); 
    Target.Invalidate(true); 
    Target.Update(); 
}