C++ /WinRT软件WinUI 3:如何在关闭主窗口前显示内容对话框?

nzrxty8p  于 2022-12-15  发布在  其他
关注(0)|答案(1)|浏览(276)

我试图显示一个内容对话框,以确保用户在选择窗口的关闭按钮时确认关闭。但在WinUI3中,我找不到CloseRequested事件。
我尝试使用AppWindow和Hwnd Interop和AppWindow.Closing,但它不工作。在我单击关闭按钮后,没有发生任何事情。
我用的是云母窗,我相信问题一定在这里。

m_closedRevoker = this->Closed(winrt::auto_revoke, [&](IInspectable const&, WindowEventArgs const& e)
    {
        if (!_closing)
        {
            _closing = true;
            e.Handled(true);
            if (have_saved)
            {
                DispatcherQueue().TryEnqueue([&](auto&& ...)
                    {
                        if (nullptr != m_backdropController)
                        {
                            m_backdropController.Close();
                            m_backdropController = nullptr;
                        }
                if (nullptr != m_dispatcherQueueController)
                {
                    m_dispatcherQueueController.ShutdownQueueAsync();
                    m_dispatcherQueueController = nullptr;
                }
                Close();
                    });
            }
            else
            {
                winrt::Microsoft::UI::Xaml::Controls::ContentDialog dialog;
                dialog.XamlRoot(Content().XamlRoot());
                dialog.Title(winrt::box_value(L"Save ?"));
                dialog.PrimaryButtonText(L"Yes");
                dialog.SecondaryButtonText(L"No");
                dialog.CloseButtonText(L"Cancel");
                dialog.DefaultButton(winrt::Microsoft::UI::Xaml::Controls::ContentDialogButton::Primary);
                dialog.PrimaryButtonClick([&](auto&& ...)
                    {
                        if (save_data(winrt::Lexical_Frequency::implementation::amount))
                        {
                            DispatcherQueue().TryEnqueue([&](auto&& ...)
                                {
                                    if (nullptr != m_backdropController)
                                    {
                                        m_backdropController.Close();
                                        m_backdropController = nullptr;
                                    }
                            if (nullptr != m_dispatcherQueueController)
                            {
                                m_dispatcherQueueController.ShutdownQueueAsync();
                                m_dispatcherQueueController = nullptr;
                            }
                            Close();
                                });
                        }
                    });
                dialog.SecondaryButtonClick([&](auto&& ...)
                    {
                        DispatcherQueue().TryEnqueue([&](auto&& ...)
                            {
                                if (nullptr != m_backdropController)
                                {
                                    m_backdropController.Close();
                                    m_backdropController = nullptr;
                                }
                                if (nullptr != m_dispatcherQueueController)
                                {                                       m_dispatcherQueueController.ShutdownQueueAsync();
                                    m_dispatcherQueueController = nullptr;
                                }
                                Close();
                            });
                    });

                dialog.ShowAsync().Completed([&](auto&& ...)
                    {
                        _closing = false;
                    });
            }
        }
    });
gojuced7

gojuced71#

下面是一个基于Window.Closed event的解决方案,其中包含一个我们可以使用的Handled property
在主窗口.cpp:

namespace winrt::WinUIApp1CPP::implementation
{
    MainWindow::MainWindow()
    {
        InitializeComponent();

        _closing = false;
        Closed([&](IInspectable const&, WindowEventArgs const& e)
            {
                if (!_closing)
                {
                    _closing = true;
                    e.Handled(true);

                    ContentDialog dialog;
                    dialog.XamlRoot(Content().XamlRoot());
                    dialog.Title(box_value(L"Do you really want to close the app?"));
                    dialog.PrimaryButtonText(L"Yes, close");
                    dialog.CloseButtonText(L"No, cancel");
                    dialog.DefaultButton(ContentDialogButton::Close);
                    dialog.PrimaryButtonClick([&](auto&& ...)
                        {
                            DispatcherQueue().TryEnqueue([&](auto&& ...)
                                {
                                    Close();
                                });
                        });

                    dialog.ShowAsync().Completed([&](auto&& ...)
                        {
                            _closing = false;
                        });
                }
            });
    }
}

使用主窗口.h:

namespace winrt::WinUIApp1CPP::implementation
{
    struct MainWindow : MainWindowT<MainWindow>
    {
        MainWindow();
        ...
        bool _closing;
        ...
   };
}

不管怎样,C#中的等价物是:

public MainWindow()
{
    InitializeComponent();

    var closing = false;
    Closed += async (s, e) =>
    {
        if (!closing)
        {
            closing = true;
            e.Handled = true;

            var dialog = new ContentDialog();
            dialog.XamlRoot = Content.XamlRoot;
            dialog.Title = "Do you really want to close the app?";
            dialog.PrimaryButtonText = "Yes, close";
            dialog.CloseButtonText = "No, cancel";
            dialog.DefaultButton = ContentDialogButton.Close;
            dialog.PrimaryButtonClick += (s, e) => DispatcherQueue.TryEnqueue(Close);
            var result = await dialog.ShowAsync();
            closing = false;
        }
    };
}

注:不需要使用DispatcherQueue.TryEnqueue,但如果不使用DispatcherQueue.TryEnqueue,Close()调用当前会导致WinUI3崩溃...

相关问题