1

设想:

  • CustomWindow带有自定义模板/ WindowChrome的WPF 窗口 ( ) 。
  • 问题:尝试在Loaded事件 throws中关闭窗口NullReferenceException
  • 解决方法:
    1. 如果我注释掉WindowChromesetter,那么它就可以工作。
      • 但失去自定义镀铬
    2. 如果我在关闭窗口之前延迟了任意时间,那么它就可以工作。
      • 使用延迟感觉不对

问题:

只有延迟解决方法允许我 1) 保留我的自定义窗口镶边和 2) 不引发异常。

但是延迟解决方案感觉就像一个黑客。

有一个更好的方法吗?


自定义窗口 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()

环境:

  • 视窗 10 专业版
  • 视觉工作室 2017
  • .NET 4.6.1

解决方案

将代码更改为以下作品:

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

1 回答 1

1

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

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

我不完全确定是否DispatcherPriority.Background正确,但基本思想是您的窗口镶边会以某些工作优先级进行自我初始化,并且您的关闭应该以较低的优先级进行,因此它将被推迟。

于 2017-11-27T09:48:01.093 回答