如何制作“部分”模态对话框?

时间:2009-04-27 17:08:08

标签: winforms

有没有办法开始以模态方式显示一个对话框,而不是隐藏它,以便在将其更改为非模态对话框时保持可见?

我想显示一个对话框,阻止显示对话框的方法。然后,当用户单击我想要的对话框上的“完成”按钮时:

  • 要保持可见的对话框。
  • 控制返回显示对话框的方法。

我通过在单独的STA线程上运行对话框并使用事件来阻止主UI线程直到按下“完成”来实现此结果,但是这个方法有一个问题:你可以点击关闭对话框可见时,“主”窗口的按钮,隐藏对话框时主窗口关闭。

更新

感谢目前为止的回复。对不起 - 看起来我在太多的背景和不够之间得到了平衡。

该表单实际上是一个模态“向导”对话框 - 它出现,以模态方式位于主应用程序的前面,然后被隐藏。因此,就用户而言,没有非标准的怪异。唯一的区别是对话框是由来自UI线程的一系列回调驱动的,所以我不认为它的真实模态(通过调用ShowDialog)的生命周期是可行的。第一个回调必须显示对话框,然后在用户通过对话框UI设置其首选项时阻止。之后,对话框保持可见并显示进度条页面,同时从UI线程进行各种其他回调。最终表格被隐藏了。表单启动时,用户不与主窗口交互。就他们而言,它应该看起来是主要UI线程的100%模态。

(表单是Visual Studio向导的对话框 - 这些是由UI线程上的一系列回调驱动的)。另一种方法是显示对话框,隐藏它,立即显示最顶层的“进度”表单然后隐藏它,但我认为显示单个对话框对用户来说是更加无缝的体验。

再次 - 抱歉混乱!

6 个答案:

答案 0 :(得分:6)

也许你想重新考虑你的互动模式?你打算如何向用户解释这个?他们有一个关于计算机程序如何工作的内在模型,你最好有一个很好的理由来打破它。他们了解模态对话,他们了解非模态对话,他们了解检查员。选择一个,然后应用它。

模态对话框用于短时间交互。他们不应该阻止退出应用程序。用户可以控制交互,程序只提供所需的最少限制。

[解释后,替换] 在模态对话框中显示进度条有什么问题?一旦开始处理即可 单击,禁用所有按钮,只保持取消按钮处于活动状态?如果需要很长时间,用户可能想要中止操作。只有在完成处理后才关闭对话框。

答案 1 :(得分:1)

您可以使用无模式对话框,然后让主UI检查用户是否单击了“完成”按钮。如果无模式对话框已打开但尚未单击完成,则不要响应主窗体中的任何用户操作...

答案 2 :(得分:1)

这只是一个可怕的想法 - 它完全是非标准的行为,你会跳过各种各样的箍来获得一些工作,这会让你的用户感到非常困惑。

答案 3 :(得分:1)

与此处陈述的大多数其他答案一样,您实施的非标准UI元素会让大多数用户感到困惑。

如果对话框保持可见只是为了提供对数据的只读访问权限,那么为什么不正常关闭对话框窗口并使用对话框窗口中的数据打开应用程序中的侧栏窗口?

如果对话框仍然可见,以允许用户继续在其中进行更新,那么也许,它不应该是开始时的模态。

重点是,在不破坏标准UI隐喻的情况下,您可以通过几种不同的方式完成任务。

答案 4 :(得分:0)

我会从你的应用程序的侧面或底部做一个弹出窗口,将其他东西推开。如果它是用户可能需要查看或与之交互的其他内容之上,那么它只会让他们烦恼。

答案 5 :(得分:0)

我发现在交互阻塞阶段在主UI线程上显示一个看不见的模态对话框效果很好。

隐藏的模态对话框设置(因此不可见):ShowInTaskBar = false,FormBorderStyle = None,size = {0,0},Opacity = 0%,StartupPosition = CenterParent。

使用ShowDialog在UI线程上显示隐藏的对话框。可见对话框显示在单独的STA线程上。在主UI线程上调用hiddenDialog.ShowDialog之前,该线程已启动。

当希望初始阻塞状态完成时,可见对话框隐藏hiddenDialog。这会阻止主UI线程阻塞。

代码的重要部分:

void LaunchWizardForm(s)
{
  // Show the wizard on its own thread.
  ThreadStart t = () =>
  {
    _wizard = new WizardForm(s);
    Application.Run(new ApplicationContext(_wizard));
  };
  var thread = new Thread(t);
  thread.SetApartmentState(ApartmentState.STA);
  thread.Start();

  // Block this (main UI) thread
  _hiddenForm.ShowDialog();
}

void EndModalEpisode()
{
    _hiddenForm.Invoke((Action) (() => _hiddenForm.Hide()));
}