Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/.net/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 显示新窗体时控件为白色_C#_.net_Forms_Controls_Paint - Fatal编程技术网

C# 显示新窗体时控件为白色

C# 显示新窗体时控件为白色,c#,.net,forms,controls,paint,C#,.net,Forms,Controls,Paint,因为这是一个相当大的项目,我经常需要从一个类中访问其他形式的对象,所以我首先在我的program.cs类中创建一个类型为“MainForm”的静态变量,它是一个Windows窗体 在DataManger.cs类中,我实例化对象“Program.MainFormObj=newmainform()”,然后调用Show方法以显示我的表单。看起来表单的绘制事件还没有完成,但它确实在绘制一些控件时启动。大概是因为主线程(这都在一个主线程上运行)被下一条语句“占用”。我想,不管已知的问题如何,我都会使用Ap

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

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


我真的卡住了。尽管在这里和使用谷歌进行了广泛的搜索,我还是找不到合适的答案。我是这样做的:但是给定的解决方案不适合我的解决方案。非常感谢您的帮助。

如果这是一个大型项目,请立即投入时间对其进行重构

  • 考虑一个MVC模式。您可以,而不仅仅是更新的UI技术
  • 如果您不选择WinForms,则至少需要单独的UI和数据(是您的朋友)
  • 当不同的表单共享公共功能时,构建可重用组件
从中期来看,与WinForms的工作方式抗争比现在投入时间做好事情要昂贵得多

如果你对技术有任何选择,不妨考虑WPF。WPF有一个学习曲线,但现在很值得投资学习

更新

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

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

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

然而,当我尝试这样做时,我发现
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代码:


您至少违反了Winforms编程的两条“永远不要这样做!”规则。你可能正在做的其他事情只能被猜测。以目前的形式,这不是一个可以回答的问题,请访问您当地的书店或图书馆,查找有关正确的Winforms编程技术的书籍。谢谢您的回复。不幸的是,对于这个项目,由于时间限制,我除了使用WinForms之外别无选择。今年夏天,我肯定会研究MVC模式和WPF,我同意从长远来看,这更有益。您知道我可以在解决方案的当前结构中实现的解决此问题的方法吗?没有足够的信息来确定问题是什么。你能创建一个小的测试用例来演示这个问题并发布代码,或者至少是相关的部分吗?Thx一堆,效果很好。我实际上尝试过这样一种解决方案,但我没有在LoginForm上调用Invoke方法,而是在MainForm上调用了它,它引发了一个异常,因为它尚未创建。我的理解是,当调用Invoke方法时,它会在该线程上执行lambda expressions块中的操作,因此不存在非法的跨线程操作。如果可以从LoginForm调用Invoke方法,我认为这是错误的。如果你能再帮我理解,我会很感激的。我有什么办法可以在这里给你某种形式的声誉吗?你必须完全创建并显示该形式,然后才能调用它,对吗。调用Invoke(或BeginInvoke)将调用封送到UI线程。如果你想赢得一些声誉,正确的方法是接受这个答案:-)(打勾使其变为绿色)