【问题标题】:ShowDialog without Blocking CallerShowDialog 不阻塞调用者
【发布时间】:2011-08-24 02:24:27
【问题描述】:

我有一个强大的命名程序集。

以前有人问过这个问题……但只是出于不同的目的。

我有一个 Form 基类。当实现类在基类IsBusy 上设置属性时。我想阻止与表单的所有交互(设置 Enabled = false 是不够的 - 我还想阻止移动、调整大小、关闭等......并且我不希望我的控件在 IsBusy == true 时看起来被禁用)并在前面显示一个弹出式加载表单(带有加载动画的透明、无边框表单)。

在我的加载动画表单上调用 ShowDialog 可以阻止调用表单上的交互...但显然我还希望调用表单代码继续执行。

现在我正在使用 new LoadingForm().Show(),然后在我的调用 Form 上处理 WndProc,如果 IsBusy == true 我抑制所有 WndProc 消息......但我不喜欢这种方法。它也可以防止表单重新绘制,这是我不想要的。

如果我知道在IsBusy == true...时允许正确重绘的所有不同类型的消息,我不会那么介意 WndProc 方法。

所以,我的问题是:

有没有更好的解决方案?

谁能告诉我应该让哪些 WndProc 消息通过?或者在哪里可以找到词汇表?

谢谢。

【问题讨论】:

  • “显然我也希望调用表单线程继续执行” - 只是不做任何事情,它会。看起来您正在解决一个不存在的问题。
  • 一种方法是启动一个新线程来运行操作(不是原始 UI 线程)并让该线程完成关闭“忙碌”对话框(通过调用),以便消息泵将控制恢复为原始形式。对此的一种标准封装是使用 BackgroundWorker。
  • 你是对的,使用 BackgroundWorder 可以解决这个问题。但我想集中进行此更改...而且我知道有些地方不使用 BackgroundWorker,这会使这些地方在此更改后无法正常工作。

标签: c# .net winforms


【解决方案1】:

我最终开始调用 ShowDialog:

myForm.BeginInvoke(new Action(() => new LoadingForm().ShowDialog()));

这具有让该行之后的代码继续运行并仍然阻止与 myForm 的所有交互的预期效果。

【讨论】:

  • 我不这么认为。没有人将此作为潜在的解决方案。甚至没有关闭。
  • 然后如何关闭表单? myForm.EndInvoke({这里放了什么});
  • 是的,很高兴知道!
【解决方案2】:

如果您想通过绘画,请允许WM_PAINTWM_NCPAINT

【讨论】:

【解决方案3】:

你把它弄得太复杂了。您所要做的就是防止对话框关闭。实现 FormClosing 事件(或重写 OnFormClosing,更好)并在操作繁忙时设置 e.Cancel = true。这样用户就无法干扰您的进程。

这一切都假设您使用工作线程来实现操作。

【讨论】:

  • 我认为您没有正确理解这个问题。我不想依赖每个继承的 Form 只能从后台线程安全地设置 IsBusy = true 。我想阻止的不仅仅是关闭,而是所有的互动。
  • 你必须给出一个在这种情况下可能发生的交互的例子。没有我能想到的。
  • 好的,加载窗口充当对话框的唯一方法是我在其上调用 ShowDialog,对吗?如果我这样做,它会阻塞调用线程。因此,设置 myForm.IsBusy = true 的人将挂在该行并且永远没有机会将 IsBusy 设置回 false ......所以加载表单将永远保持不变。我在这里误解了什么吗?
  • 例如在 BackgroundWorker 的 RunWorkerCompleted 事件处理程序中将其设置回 false 不是问题。
  • 你是对的。我是说它阻塞了线程……但它真正在做的是开始一个新的消息循环。无论哪种方式,它都有相同的效果。调用 new Form().ShowDialog() 将 1) 在调用行阻塞并开始一个新的消息循环。 2)防止交互将来自新形式的背后。第 1 点是我需要避免的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-16
  • 2016-03-24
  • 2010-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多