在 Loaded 事件中调用 Close() 时 WPF 自定义 WindowChrome 异常

WPF Custom WindowChrome exception when invoke Close() in Loaded event

场景:

问题:

只有延迟解决方法允许我 1) 保留我的自定义 window chrome 和 2) 不抛出异常。

但是延迟解决方案感觉像是一个 hack。

有更好的方法吗?


自定义窗口xaml

<Style TargetType="v:CustomWindow">
    <!-- Workaround 1: Works when commented out -->
    <Setter Property="WindowChrome.WindowChrome">
        <Setter.Value>
            <WindowChrome UseAeroCaptionButtons="False" />
        </Setter.Value>
    </Setter>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type v:CustomWindow}">
                <DockPanel Background="White">
                    <!-- Caption bar -->
                    <Grid Background="Cyan" DockPanel.Dock="Top">
                        <Grid Margin="5">
                            <!-- Title -->
                            <TextBlock FontSize="20" Text="{TemplateBinding Title}" />

                            <!-- Close button -->
                            <Button Width="30" Command="SystemCommands.CloseWindowCommand"
                                    HorizontalAlignment="Right"
                                    WindowChrome.IsHitTestVisibleInChrome="True"
                                    Content="Close" />


                        </Grid>
                    </Grid>

                    <!-- Window content -->
                    <ContentPresenter Content="{TemplateBinding Content}" />
                </DockPanel>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

用法

var dialog = new CustomWindow();
dialog.Loaded += async delegate
{
    // On loaded, do something, then close immediately

    // await Task.Delay(10); // <-- Workaround 2: Uncomment this, and it seems to work
    dialog.Close();
};
dialog.ShowDialog();

堆栈跟踪:

at System.Windows.Shell.WindowChromeWorker._ExtendGlassFrame()
at System.Windows.Shell.WindowChromeWorker._UpdateFrameState(Boolean force)
at System.Windows.Shell.WindowChromeWorker._ApplyNewCustomChrome()
at System.Windows.Shell.WindowChromeWorker._WindowSourceInitialized(Object sender, EventArgs e)
at System.Windows.Window.OnSourceInitialized(EventArgs e)
at System.Windows.Window.CreateSourceWindow(Boolean duringShow)
at System.Windows.Window.CreateSourceWindowDuringShow()
at System.Windows.Window.SafeCreateWindowDuringShow()
at System.Windows.Window.ShowHelper(Object booleanBox)
at System.Windows.Window.Show()
at System.Windows.Window.ShowDialog()

环境:

解决方案

将代码更改为以下工作:

var dialog = new CustomWindow();
dialog.Loaded += delegate
{
    Dispatcher.BeginInvoke(new Action(
        delegate
        {
            // On loaded, do something, then close immediately
            dialog.Close();
        })
    );
};
dialog.ShowDialog();

考虑使用 Dispatcher 延迟关闭,直到所有典型工作完成:

Dispatcher.BeginInvoke(new Action(ShutMeDown), DispatcherPriority.Background);

我不完全确定 DispatcherPriority.Background 是否正确,但基本思想是您的 window chrome 将使用一些工作优先级自行初始化,并且您的关机应该发生的优先级较低,因此将被推迟。