如何在加载 Window 之前使用 Dispatcher.PushFrame?

How to use Dispatcher.PushFrame before the Window is loaded?

我有一个功能,我必须同步等待用户输入。我无法控制从哪个线程调用此函数,因此调用者可能已经在 UI 线程或不在(在这种情况下,我将不得不使用 Dispatcher)。

为此,我一直在使用 DispatcherFrameDispatcher.PushFrame,以便 UI 继续响应,即使从 UI 线程。

这是一个小演示(请注意,这是一个非常愚蠢的示例,但代表了我正在努力实现的目标):

MainWindow.xaml

<StackPanel VerticalAlignment="Center"
            HorizontalAlignment="Center"
            Orientation="Vertical"
            Width="500">
    <TextBox x:Name="TextBox_Result"
             Margin="0 0 0 10" />

    <Button x:Name="Button_ContinueExecution"
            Content="..." />
</StackPanel>

MainWindow.xaml.cs

string PromptUserForInputSynchronously()
{
    string result = null;

    if (Application.Current.Dispatcher.CheckAccess())
    {
        var nestedFrame = new DispatcherFrame(true);

        Button_ContinueExecution.Click += (s, e) =>
        {
            nestedFrame.Continue = false;
            result = TextBox_Result.Text;
        };

        Button_ContinueExecution.Content = "Click to resume execution";

        Console.WriteLine("Waiting for click...");

        Dispatcher.PushFrame(nestedFrame);

        Console.WriteLine("Clicked with text: " + result);
    }
    else
    {
        result = Dispatcher.CurrentDispatcher.Invoke(() => PromptUserForInputSynchronously());
    }

    return result;
}

现在,这个似乎可以工作了,除非(我猜)MainWindow 还没有加载。看看:

public MainWindow()
{
    InitializeComponent();

    // This works
    Loaded += (s, e) => PromptUserForInputSynchronously();

    // This hangs the application
    PromptUserForInputSynchronously();
}

我有什么方法可以让它工作吗?这是最好的方法吗?

@编辑:背景

我想要实现的是创建一个类似于 MessageBox 的对话框(但看起来更好)。显示时,对话框会阻止当前线程(但保持 UI 响应,以防该线程是 Dispatcher 线程),直到用户单击其中一个按钮。

我的目标是稍后以 NuGet 包的形式提供它,这就是为什么我在不同的场景中测试它(比如从构造函数内部调用它)。

您的代码抛出错误的原因是 Dispatcher 此时尚未启动。默认情况下,您的入口点将实例化 MainWindow 以显示它。确切的细节不是我曾经发现的用途,但是,Dispatcher 也已启动。显然,只有在实例化 mainwindow 之后才会发生这种情况。

因此,您必须更改一些启动基础才能获得此 "working"。

您可以覆盖应用程序启动并尝试确保 sta 线程和调度程序在实例化 mainwindow 之前运行。不过这是个坏主意。

除了在 mainwindow 构造函数中实例化之外,您不应该尝试做任何事情。原因是如果您遇到任何错误,因为您根本没有 main window。您的应用程序将关闭,您的用户将开始抱怨。

我建议您将此原则扩展到所有 wpf windows。尽量减少你在他们的构造函数中所做的事情。不要中断实例化,尤其是不要尝试从 window.

的构造函数中显示其他 window

如果您需要在显示 window 之前发出消息或获得一些用户输入,那么只需先单独执行即可。如果您需要显示带有模态对话的 window,则首先显示 window,然后使用稍后的事件来驱动您的对话 - 显示。