2010-05-31 38 views
3

我的应用程序具有以下UI配置:当可见性改变时,mdi儿童形式绘制缓慢

主窗体是一个MDI容器。其子表格附在TabStrip

每个用户都有他的一组子表单。根据活动用户的不同,仅显示该用户的子表单以及选项卡。

这是通过检查主窗体的MdiChildren并将它们的Visible属性设置为false/true,具体取决于活动用户。

 foreach (Form item in MdiChildren) 
     { 
      if (((OfficeFormEx)item).UserID == (int)e.NewTab.Tag) 
      { 
       item.Visible = true; 
      } 
      else 
      { 
       item.Visible = false; 
      } 
     } 

这有两个不良影响。一个是每个孩子的形式都是连续重绘,这是丑陋而缓慢的。另一个原因是由于某种原因,形式从最大化到正常,有效地将它们从主要形式中分离出来。

是否有任何方法只显示其中一个子窗体,比如用户以前正在查看的窗体,并让其他人留在后台?最大化/正常的事情并不是什么大事,因为我可以再次手动使其最大化。

+0

+1你的问题是为了学习@Hans Passant已经明确解释的东西而进行的。谢谢! =) – 2010-06-01 12:34:00

回答

1

我最终解决了这个问题,所以这里是一个迟来的写作。

Will Marcouiller建议SuspendLayout()ResumeLayout(),这没有奏效。这使我调查了这两种方法实际上做了什么,并得出结论,我需要的是一种方法来阻止主要表单在MDI儿童操作正在进行时重新绘制。

这反过来导致以下两种静态实用程序方法暂停对给定控件重新绘制。就我而言,暂停重新绘制主表格导致了大幅度的加速。

/// <summary> 
/// suspends drawing on a control and its children 
/// </summary> 
/// <param name="parent"></param> 
public static void SuspendDrawing(Control control) 
{ 
    SendMessage(control.Handle, WM_SETREDRAW, false, 0); 
} 

/// <summary> 
/// resumes drawing on a control and its children 
/// </summary> 
/// <param name="parent"></param> 
public static void ResumeDrawing(Control control) 
{ 
    SendMessage(control.Handle, WM_SETREDRAW, true, 0); 
    control.Refresh(); 
} 
2

乍一看,我会看看Form.WindowsState属性,如果你还没有。我怀疑如果您在设计时将此属性设置为FormWindowState.Maximized,则在设置其Visible属性true/false时,将会更改此属性。

对于“[...]每个孩子的表格都会被连续重绘[...]” - 事情,您是否尝试在活动用户的表单验证开始时使用SuspendLayout()方法,之后再调用ResumeLayout()

编辑#1

  • 我会建议你只加载所需的Form当前用户。

这样做会降低应用程序所使用的内存量,再加上,应大幅缩短包含MdiChildren集合属性中表格的数量。然后,如果仍然需要,迭代集合会更快。

如果这不是一个选择,那么也许使用的LINQ可能帮助:

var visibleForms = from f in MdiChildren 
        where (((OfficeFormEx)f).UserID == (int)e.NewTab.Tag) 
        select f; 

var invisibleForms = from f in MdiChildren 
        where (((OfficeFormEx)f).UserID != (int)e.NewTab.Tag) 
        select f 

visibleForms.ToList().ForEach(f => f.Visible = true); 
invisibleForms.ToList().ForEach(f => f.Visible = false); 

如果你使用.NET 4.0,也许这会是一个很好的候选PLINQ

请提供反馈意见,以便我们找到解决方案。 =)

+0

不幸的是,这两者都没有帮助。 – dandan78 2010-05-31 13:57:59

+0

然后,为了帮助我们帮助您,请提供一些代码示例,说明您正在做什么来检查MdiChild是否可见,等等。考虑到Mdi应用程序通常没有加载和打开所有可能的MdiChildren申请开始。如果理解正确,也许让用户打开她/他需要的MdiChild将是明智的。 – 2010-05-31 14:02:32

+0

我刚添加了代码。在这种情况下,所有可能的MDI儿童都会随时加载,因为每个用户都有固定数量的表单,用于显示应用程序的各个部分。当活动用户改变时,用户需要只看到他的表单子集。 – dandan78 2010-05-31 14:12:42

2

没有代码片段,你的问题不是很清楚。然而,你正在与Windows MDI实施做斗争。它不支持的一件事是隐藏一个子窗口,它最多只能被最小化。 Windows窗体通过销毁窗口句柄来实现Visible属性,并在Visible属性再次设置为True时重新创建它。该窗口的新实例将不会最大化。

它也不支持将焦点切换到当前窗口最大化时的子窗口。 WF的解决方法是强制活动子窗口回到正常状态。

MDI模型根本不适合在最大化状态下显示子窗口。要获得标签界面,请使用TabControl并在其标签页上显示UserControls。

+0

对不起,如果我遗漏了重要的细节,但我真的没有看到包括foreach循环的任何一点。 :) 您对MDI的评论的其余部分几乎总结了我一直在贬低的东西。 (但是,我可以发誓说,其中一些工作在我之前的项目中,我必须去看看。 感谢有关发动机罩下方会发生什么的信息 – dandan78 2010-05-31 13:57:26

+0

+1这些是值得考虑的宝贵信息在处理MDI应用程序时。 – 2010-06-01 12:32:03