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

时间:2021-11-22 06:59:11

Is there a way to start off showing a dialog modally, but then instead of hiding it, to keep it visible while changing it to a non-modal dialog?

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

I want to show a dialog, blocking the method that shows the dialog. Then when the user clicks the 'Finish' button on the dialog I want:

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

  • The dialog to remain visible.
  • 该对话框保持可见。

  • Control to return to the method that showed the dialog.
  • 控制返回显示对话框的方法。

I've achieved this result by running the dialog on a separate STA thread, and using an event to block the main UI thread until 'Finish' is pressed, but there's a catch to this method: you can click on the close button of the 'main' window while the dialog is visible, and the main window closes when the dialog is hidden.

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

Update

Thanks for the responses so far. Sorry - it looks like I got the balance wrong between too much background and not enough.

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

The form is effectively a modal 'wizard' dialog - it appears, sits in front of the main app modally, and then is hidden. So as far as the user's concerned there's no non-standard weirdness going on. The only difference is that the dialog is driven from a series of callbacks from the UI thread, so I don't think making it truly modal (via a call to ShowDialog) for its lifetime would work. The first callback must show the dialog, and then block while the user sets their preferences via the dialog UI. After that, the dialog stays visible and displays a progress bar page while various other callbacks are made from the UI thread. Eventually the form is hidden. The user isn't interacting with the main window while the form is up. As far as they're concerned, it should appear to be 100% modal wrt the main UI thread.

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

(The form is a dialog for a Visual Studio wizard - these are driven from a series of callbacks on the UI thread). An alternative would be to show the dialog, hide it, immediately show a topmost 'progress' form instead and then hide that, but I think showing a single dialog is more seamless an experience for the user.

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

Again - sorry for the confusion!

再次 - 抱歉混乱!

6 个解决方案

#1


Perhaps you want to rethink your interaction model? How are you going to explain this to your users? They have an internalized model of how computer programs work, and you better have a very good reason to break that. They know about modal dialogs, they know about non-modal dialogs, they know about inspectors. Choose one, and apply it.

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

Modal dialogs are made for short-time interaction. They should not block exiting the application. The user is in control of the interaction, the program only provides the minimum of restrictions needed.

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

[after the explanation, replaced] What's wrong with showing the progress bar in the modal dialog? Start processing once ok is clicked, disabling all buttons, only keeping the cancel button active? If it takes a long time, the user might want to abort the action. Only close the dialog when you're finished processing.

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

#2


You could use a modeless dialog then have your main UI check if the user has clicked the Finished button. If the modeless dialog is open but Finished hasn't been clicked then don't respond to any users actions in the main form...

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

#3


This is just a terrible idea - it's completely non-standard behavior and you're going to jump through all kinds of hoops to get something working that is just going to horribly confuse your users.

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

#4


Like most of the other answers here stated, you're implement non-standard UI elements that will be confusing to most users.

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

If the dialog remains visible just to provide read-only access to the data, then why not have dialog window close normally and open a side-bar window in your application with the data from the dialog window?

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

If the dialog remains visible to allow the users to continue making updates in it, then perhaps, it shouldn't be modal to begin with.

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

Point is, there's a couple different ways you can accomplish your task without breaking standard UI metaphors.

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

#5


I'd make it a flyout from the side or bottom of your app that shoves other things out of the way. If it's on top of other stuff that the user might need to see or interact with then it's just gonna annoy them.

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

#6


I found that showing an an invisible modal dialog on the main UI thread during the blocking stage of the interaction works great.

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

Hidden modal dialog settings (so it's not visible): ShowInTaskBar=false, FormBorderStyle=None, size={0,0}, Opacity=0%, StartupPosition=CenterParent.

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

The hidden dialog is shown on the UI thread using ShowDialog. The visible dialog is shown on a separate STA thread. The thread is kicked off before calling hiddenDialog.ShowDialog on the main UI thread.

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

The visible dialog hides hiddenDialog when it wants the initial blocking state to complete. This stops the main UI thread from blocking.

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

The important bits of code:

代码的重要部分:

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()));
}

#1


Perhaps you want to rethink your interaction model? How are you going to explain this to your users? They have an internalized model of how computer programs work, and you better have a very good reason to break that. They know about modal dialogs, they know about non-modal dialogs, they know about inspectors. Choose one, and apply it.

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

Modal dialogs are made for short-time interaction. They should not block exiting the application. The user is in control of the interaction, the program only provides the minimum of restrictions needed.

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

[after the explanation, replaced] What's wrong with showing the progress bar in the modal dialog? Start processing once ok is clicked, disabling all buttons, only keeping the cancel button active? If it takes a long time, the user might want to abort the action. Only close the dialog when you're finished processing.

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

#2


You could use a modeless dialog then have your main UI check if the user has clicked the Finished button. If the modeless dialog is open but Finished hasn't been clicked then don't respond to any users actions in the main form...

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

#3


This is just a terrible idea - it's completely non-standard behavior and you're going to jump through all kinds of hoops to get something working that is just going to horribly confuse your users.

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

#4


Like most of the other answers here stated, you're implement non-standard UI elements that will be confusing to most users.

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

If the dialog remains visible just to provide read-only access to the data, then why not have dialog window close normally and open a side-bar window in your application with the data from the dialog window?

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

If the dialog remains visible to allow the users to continue making updates in it, then perhaps, it shouldn't be modal to begin with.

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

Point is, there's a couple different ways you can accomplish your task without breaking standard UI metaphors.

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

#5


I'd make it a flyout from the side or bottom of your app that shoves other things out of the way. If it's on top of other stuff that the user might need to see or interact with then it's just gonna annoy them.

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

#6


I found that showing an an invisible modal dialog on the main UI thread during the blocking stage of the interaction works great.

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

Hidden modal dialog settings (so it's not visible): ShowInTaskBar=false, FormBorderStyle=None, size={0,0}, Opacity=0%, StartupPosition=CenterParent.

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

The hidden dialog is shown on the UI thread using ShowDialog. The visible dialog is shown on a separate STA thread. The thread is kicked off before calling hiddenDialog.ShowDialog on the main UI thread.

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

The visible dialog hides hiddenDialog when it wants the initial blocking state to complete. This stops the main UI thread from blocking.

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

The important bits of code:

代码的重要部分:

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()));
}