代码之家  ›  专栏  ›  技术社区  ›  mackenir

如何创建“部分”模态对话框?

  •  0
  • mackenir  · 技术社区  · 17 年前

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

    • 对话框将保持可见。
    • 控件返回到显示对话框的方法。

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

    使现代化

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

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

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

    再一次-抱歉造成混乱!

    6 回复  |  直到 17 年前
        1
  •  6
  •   Stephan Eggermont    17 年前

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

    [解释后,替换] 在模式对话框中显示进度条有什么问题?确定后立即开始处理 是否单击,禁用所有按钮,仅保持“取消”按钮处于活动状态?如果需要很长时间,用户可能希望中止该操作。仅在完成处理后关闭对话框。

        2
  •  1
  •   Shea    17 年前

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

        3
  •  1
  •   17 of 26    17 年前

    这只是一个糟糕的想法——这是完全不标准的行为,你要通过各种各样的手段来让一些东西工作起来,这会让你的用户非常困惑。

        4
  •  1
  •   SergioL    17 年前

    像这里提到的大多数其他答案一样,您正在实现非标准的UI元素,这会让大多数用户感到困惑。

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

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

        5
  •  0
  •   jcollum    17 年前

    我会在你的应用程序的侧面或底部制作一个弹出式按钮,将其他东西推到一边。如果它位于用户可能需要查看或与之交互的其他内容之上,那么它只会惹恼他们。

        6
  •  0
  •   mackenir    17 年前

    我发现在交互的阻塞阶段在主UI线程上显示一个不可见的模式对话框非常有效。

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

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

    当visible对话框希望初始阻塞状态完成时,它会隐藏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()));
    }
    
    推荐文章