1

我对 Compact Framework 中的表单绘制有一个奇怪的问题。我有一个登录对话框,它基本上是一个使用 ShowDialog 在另一个顶部打开的小表单。当刷卡时,登录对话框应该关闭,然后执行一些登录任务,然后应该激活它后面的表单。问题是登录对话框后面的表单没有被刷新,因此登录对话框直到后面的表单被某些用户操作刷新后才会被删除。这可能是由于登录任务部分进行的繁重处理,但我还没有找到解决这个问题的方法。

基本上,在执行繁重的登录任务之前,我想要一种强制应用程序关闭对话框并重新绘制所有内容的方法。我尝试了许多刷新方法,但没有任何运气:

Form loginDialog = new Form();
DialogResult result = loginDialog.ShowDialog();
loginDialog.Dispose();

//I've tried everything at this point to get the form to refresh before performing
//login tasks
this.Refresh();
this.Invalidate();
Application.DoEvents();


PerformHeavyLoginTasks();

有谁知道可能出了什么问题?谢谢

4

2 回答 2

1

好的,我想通了。问题在于背景表单上的自定义控件使用矩形等手动绘制自身。我认为这是一个紧凑的框架错误,因为我也在该控件上调用了 Refresh 和 Invalidate 并且它应该重新绘制。我必须创建一个方法来直接调用控件的 OnPaint 覆盖,因为 Invalidate 和 Refreshed 几乎被忽略了。

于 2010-09-21T18:15:46.723 回答
0

我认为,问题在于您没有完全理解这里的系统情况。

当您的前窗口(对话框)被关闭时,背景窗口(窗体)被赋予 focu 和 tol 以重新绘制对话框所在的剪辑区域。这通过 PostMessage 调用发生,该调用发送必须在 Application.Run 调用的内部弹出、翻译和分发的 Windows 消息。

从设计上讲,这是一个相当缓慢的过程,因为 UI 不应该抢占重要的东西。

如果您在 PostMessage 发生后立即进行大量处理,则这些窗口消息的处理通常会变慢,最终导致 UI 出现“锁定”或绘制速度非常慢。如果您正在执行的处理与 UI 位于同一线程上,则会加剧这种情况。

为什么你的努力没有让事情变得更好?

  • 调用 Refresh 只会发送另一条消息。该消息现在已排队等待处理,因此实际上会使事情变得更糟。
  • 调用 Invalidate 与 Refresh 的作用几乎相同,只是异步进行。再次,它使事情变得更糟。
  • DoEvents 告诉消息泵弹出、翻译和发送消息。该调度仍然必须在 UI 线程上处理,因此在线程有时间完成工作(即在您的处理之后)之前会发生注意

那么我们如何“解决”这个问题呢?

第一步通常是将处理放在单独的线程上,以允许调度程序在 UI 和处理线程之间循环任务,直到默认量子。Thgis 意味着在允许进行某种绘图之前,处理最多只能使 UI 饥饿 100 毫秒(假设线程优先级相同)。

new Thread(PerformHeavyLoginTasks)
{
    IsBackground = true
}.Start();

您可以更进一步,让 UI 在处理过程中“快速启动”(在本例中为 10 毫秒):

new Thread(new ThreadStart(delegate
    {
        Thread.Sleep(10);
        PerformHeavyLoginTasks();
    }))
{
    IsBackground = true
}.Start();

当然,如果您要显示的 UI 取决于处理结果,这可能意味着您现在需要异步处理下一个“显示”。有很多异步模式的在线资源,所以我不会在这里打败那匹死马。

于 2010-09-21T18:20:08.760 回答