【问题标题】:How to make a form stay above another如何使表格保持在另一个之上
【发布时间】:2015-01-21 13:39:11
【问题描述】:

在我的 .NET 应用程序中,如果某些任务需要一段时间才能告诉用户程序仍然有效,我将显示一个带有“请稍候”消息的表单。这种形式必须在它自己的线程中运行,因为主线程是在工作的线程,因此很忙。 I read that one can use Form.Owner for this task,但如果表单在不同的线程上运行,我认为这不起作用。

问题是等待表单可以隐藏在主表单后面,在这种情况下用户看不到它,也不能把它带到前面,因为它没有任务栏按钮(它不能有一个)。

我的问题是是否可以让等待表单保持在主表单之上而不使其成为 AlwaysOnTop 表单(它将保持在所有窗口之上)?

【问题讨论】:

  • 当然,执行此操作时会收到 IllegalOperationException。有一些方法可以解决这个问题,但是你会发现why your program deadlocked,可能是在你显示那个窗口之后小时。那是为了吓唬你。使用工作线程执行工作,使用 UI 线程显示 UI 不会有问题。

标签: c# .net windows multithreading winforms


【解决方案1】:

您的主线程不应该在工作。它应该处理 UI 而不是别的。

正确的做法是以异步方式执行所有耗时的工作(例如在单独的线程中),并将所有用户界面保留在主线程中。然后您可以通过调用Form.ShowDialog() 方法简单地显示“请稍候”消息表单。这将强制关注该对话框并将其保持在其父表单之上(不要忘记将父表单引用传递给 ShowDialog() 方法)。

如果没有代码示例,我无法准确说明这在您的特定场景中会是什么样子。但总体思路是这样的:

private void button1_Click(object sender, EventArgs e)
{
    using (Form form = MyWaitMessageForm())
    {
        form.Shown += async (sender1, e1) =>
        {
            await Task.Run(() => MyLongRunningWork());
            form.Close();
        }

        form.ShowDialog(this);
    }
}

【讨论】:

  • .ShowDialog(parent) 如果您不希望与父表单进行任何交互,如果您希望能够在父表单上执行任何操作(例如从文本框中复制文本),则为 .Show(parent) .
  • 由于 OP 明确要求拥有the wait form stay above the main form,因此正确的调用方法是ShowDialog() 而不是Show()
  • 它也停留在 Show(parent) 上方,但父级是可聚焦的。但不会出现在子窗口上方。只有两种方法可以做同样的事情,但允许不同的用法。它实际上是最接近 AlwaysOnTop 的,但仅适用于该父表单(当然需要 ShowInTaskbar=false)。
  • 我明白你的意思。我假设 OP 希望将注意力集中在对话框表单上(即用户无法与父表单交互),但他实际上并没有这么说,所以也许他不想要模态表单。在这种情况下,您是正确的:调用Show(parent) 将是合适的方法。
  • 我知道在大多数情况下这将是理想的解决方案,但在我的情况下这是不可能的。有些事情你不能在另一个线程中做。在我的情况下,这将加载 ui 并处理非线程安全的第 3 方组件,因此需要在 ui 线程中运行。但我同意,如果可能的话,这将是最好的解决方案。
【解决方案2】:

您可以为此使用Form.TopMost 属性。

您也可以使用以下代码:

protected void SetZOrder(IntPtr bottom, IntPtr top) {
    const int flags = 0x0002 | 0x0001; 
    NativeMethods.SetWindowPos(bottom, top, 0, 0, 0, 0, flags);
}

bottom - 主窗体的指针,top - 等待窗体的指针。要获取指针,请使用 Form.Handle 属性。并通过父窗体的 BeginInvoke 方法调用 SetZOrder。

【讨论】:

  • TopMost 使表单停留在所有窗口的顶部,但我希望它只停留在我的窗口上方。
  • 底部窗口的线程忙的时候不太好用,但我觉得是我能做到的最好了。谢谢!
【解决方案3】:

您可以使用Form.ShowDialog(IWin32Window)

Form1 testDialog = new Form1();
testDialog.ShowDialog(this)

【讨论】:

  • WinForms 对话框在关闭后需要释放。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-06-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多