【问题标题】:Controls are white when I display new form显示新表单时控件为白色
【发布时间】:2012-07-04 00:09:12
【问题描述】:

因为这是一个相当大的项目,而且我经常需要从一个类中访问其他形式的对象,所以我首先在我的 program.cs 类中创建了一个静态变量,类型为“MainForm”,它是一个 Windows 窗体。

从我的 DataManger.cs 类中,我实例化对象“Program.MainFormObj = new MainForm()”,然后调用 Show 方法以显示我的表单。看起来窗体的 Paint 事件没有完成,但它确实在绘制一些控件时启动。大概是因为主线程(这一切都在一个主线程上运行)被下一条语句“占用”。我想,不管已知问题如何,我都会使用 Application.DoEvents() 来临时解决这个问题。正如我想象的那样,它起作用了,但只是在一定程度上。如果我使用像 MessageBox.Show() 这样的阻塞方法,我可以在后台查看我完全完美的表单,但只要我按下“OK”并且代码继续,整个应用程序就会退出。

我真的被困住了。尽管在这里和使用谷歌都进行了广泛的搜索,但我找不到合适的答案。我做了这个线程:Form.Show() is not showing it's child controls 但给定的解决方案不适合我的解决方案。非常感谢任何帮助,谢谢。

【问题讨论】:

  • 您至少违反了两个“永远不要这样做!” Winforms 编程规则。你可能在做什么只能猜测。这不是目前形式的可回答问题,请访问您当地的书店或图书馆,查找有关正确 Winforms 编程技术的不错书籍。

标签: c# .net forms controls paint


【解决方案1】:

如果这是一个大型项目,请立即投入时间重构它。

  • 考虑一个 MVC 模式。您可以do what with WinForms,而不仅仅是更新的 UI 技术。
  • 如果您不选择 WinForms,请至少将 UI 和数据分开(Data Binding 是您的朋友)。
  • 在不同的表单共享通用功能时构建可重用的组件。

从中期来看,与 WinForms 的工作方式作斗争将比现在投入时间做正确的事情要昂贵得多。

如果您对该技术有任何选择,请考虑使用 WPF。 WPF 有一个学习曲线,但现在可能值得投资于该学习。

更新

根据您的代码示例,我发现您可能在主 UI 线程以外的线程上创建了一些表单。虽然这是允许的,但它会产生非常混乱的代码,因为表单只能从 创建它们的线程更新。

最简单的方法是更新 HandleIncomingData 以在主 UI 线程上调用 Show()

应该有一种方法可以从静态方法干净地做到这一点,如下所述:

https://stackoverflow.com/a/505361/141172

但是,当我尝试这样做时,我发现SynchronizationContext 始终为空。我确定我只是错过了一步。

我能够通过滥用LoginForm 来使事情正常进行(假设可能是错误的,该表单始终可用。如果不是,也许创建一个专门用于线程编组的特殊表单)。

黑客看起来像这样:

Program.MainForm = new MainForm();
try
{

    MessageBox.Show("Login Success.", "Login", MessageBoxButtons.OK, MessageBoxIcon.Information);

            // Abusing LoginForm's Invoke method.  Code assumes LoginForm is always available.
    Program.LoginForm.Invoke((MethodInvoker)delegate
    {
        Program.MainForm.Show();
    });


}
catch (Exception Ex)
{
    MessageBox.Show(Ex.ToString()); //Debuging purposes
}

顺便说一句,有一个出色的扩展方法可以让从非 UI 线程调用 UI 代码变得轻而易举:

https://stackoverflow.com/a/3588137/141172

【讨论】:

  • 感谢您的回复。不幸的是,对于这个项目,由于时间限制,我别无选择,只能使用 WinForms。我可以确定今年夏天要研究 MVC 模式和 WPF,我同意从长远来看它更有益。您知道我可以在解决方案的当前结构中实施的解决此问题的任何方法吗?
  • 没有足够的信息来确定问题所在。您能否创建一个小测试用例来演示该问题并发布该代码,或者至少发布相关部分?
  • 谢谢一堆,效果很好。我实际上尝试了这样的解决方案,但不是在 LoginForm 上调用 Invoke 方法,而是在 MainForm 上调用它,因为它尚未创建,因此引发了异常。据我了解,当您调用 Invoke 方法时,它会在该线程上执行 lambda 表达式块中的操作,因此不存在非法的跨线程操作。如果可以从 LoginForm 调用 Invoke 方法,我想这是错误的。如果你能帮助我理解,我将不胜感激。有什么办法可以在 SO 上给你某种形式的声誉吗?
  • 您必须完全创建并显示表单,然后才能对其调用 Invoke,正确。调用 Invoke(或 BeginInvoke)将调用编组到 UI 线程。如果您想给予一些声誉,那么适当的方法是接受这个答案:-)(点击复选标记使其变为绿色)
猜你喜欢
  • 1970-01-01
  • 2017-03-30
  • 2013-10-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-08-31
相关资源
最近更新 更多