You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinUI3中实现点击ContentDialog外部区域关闭对话框的问题

WinUI3 中实现点击 ContentDialog 外部空白区域关闭的方案

在WinUI3中,Microsoft.UI.Xaml.Window.Current.CoreWindow为空是因为WinUI3的窗口模型与UWP不同,无法直接依赖Window.Current获取CoreWindow。可以通过ContentDialog的XamlRoot关联对应的CoreWindow,实现点击外部关闭的功能。

修改后的核心实现逻辑

替换原InitializeObserving方法,并新增点击区域判断逻辑:

private void InitializeObserving()
{
    Opened += (s, e) =>
    {
        isHide = false;
        // 通过XamlRoot获取当前关联窗口的CoreWindow
        var coreWindow = XamlRoot.ContentIslandEnvironment.CoreWindow;
        coreWindow.PointerPressed += CoreWindow_PointerPressed;
    };

    Closed += (s, e) =>
    {
        isHide = true;
        // 移除事件监听,避免内存泄漏
        var coreWindow = XamlRoot.ContentIslandEnvironment.CoreWindow;
        coreWindow.PointerPressed -= CoreWindow_PointerPressed;
    };
}

private void CoreWindow_PointerPressed(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.PointerEventArgs args)
{
    if (!isHide)
    {
        // 获取对话框的屏幕坐标范围
        var dialogBounds = GetBoundingRect();
        var pointerPosition = args.CurrentPoint.Position;

        // 仅当点击位置在对话框外部时执行关闭逻辑
        if (!dialogBounds.Contains(pointerPosition))
        {
            if (_actionCommand != null)
                _actionCommand.Execute(null);
            else
                Hide();
        }
    }
}

// 辅助方法:获取ContentDialog的屏幕坐标区域
private Rect GetBoundingRect()
{
    var transform = this.TransformToVisual(null);
    var position = transform.TransformPoint(new Point(0, 0));
    return new Rect(position.X, position.Y, this.ActualWidth, this.ActualHeight);
}

关键说明

  1. CoreWindow获取方式变更:WinUI3中ContentDialog的XamlRoot.ContentIslandEnvironment.CoreWindow可正确获取当前关联的窗口核心对象,取代UWP中Window.Current.CoreWindow的用法。
  2. 点击区域精准判断:新增GetBoundingRect方法获取对话框的屏幕范围,避免点击对话框内部区域误触发关闭逻辑。
  3. 事件清理:在Closed事件中必须移除PointerPressed监听,防止内存泄漏。

完整修改后的CustomContentDialog类代码

public sealed partial class CustomContentDialog : ContentDialog, INotifyPropertyChanged
{
    private string _titleText = string.Empty;
    private string _messageText = string.Empty;
    private string _buttonText = string.Empty;
    private DispatcherTimer _timer = null;
    private int _timerInterval = 0;
    private IMvxCommand _actionCommand = null;
    public bool isHide = true;

    public CustomContentDialog()
    {
        InitializeComponent();
        InitializeObserving();
        InitializeView();
    }

    public CustomContentDialog(string titleText, string messageText, string buttonText, IMvxCommand actionCommand = null)
    {
        _titleText = titleText;
        _messageText = messageText;
        _buttonText = buttonText;
        _actionCommand = actionCommand;

        InitializeComponent();
        InitializeObserving();
        InitializeView();
    }

    public CustomContentDialog(string titleText, string messageText, string buttonText, int timerInterval, IMvxCommand actionCommand = null)
    {
        _titleText = titleText;
        _messageText = messageText;
        _buttonText = buttonText;
        _timerInterval = timerInterval;
        _actionCommand = actionCommand;

        InitializeComponent();
        InitializeObserving();
        InitializeView();
    }
    
    private void InitializeObserving()
    {
        Opened += (s, e) =>
        {
            isHide = false;
            var coreWindow = XamlRoot.ContentIslandEnvironment.CoreWindow;
            coreWindow.PointerPressed += CoreWindow_PointerPressed;
        };

        Closed += (s, e) =>
        {
            isHide = true;
            var coreWindow = XamlRoot.ContentIslandEnvironment.CoreWindow;
            coreWindow.PointerPressed -= CoreWindow_PointerPressed;
        };
    }

    private void CoreWindow_PointerPressed(Windows.UI.Core.CoreWindow sender, Windows.UI.Core.PointerEventArgs args)
    {
        if (!isHide)
        {
            var dialogBounds = GetBoundingRect();
            var pointerPosition = args.CurrentPoint.Position;
            if (!dialogBounds.Contains(pointerPosition))
            {
                if (_actionCommand != null)
                    _actionCommand.Execute(null);
                else
                    Hide();
            }
        }
    }

    private Rect GetBoundingRect()
    {
        var transform = this.TransformToVisual(null);
        var position = transform.TransformPoint(new Point(0, 0));
        return new Rect(position.X, position.Y, this.ActualWidth, this.ActualHeight);
    }

    private void InitializeView()
    {
        Title.Text = _titleText;
        Message.Text = _messageText;
        Button.Content = _buttonText;

        ProgressBar.Visibility = Visibility.Collapsed;
        if (_timerInterval > 0)
        {
            ProgressBar.Visibility = Visibility.Visible;
            ProgressBar.Maximum = _timerInterval;
            _timer = new DispatcherTimer()
            {
                Interval = TimeSpan.FromSeconds(0.5)
            };
            _timer.Tick += TimerTick;
            _timer.Start();
        }

        if (_actionCommand == null)
        {
            Button.Click += delegate
            {
                Hide();
            };
        }
        else
        {
            Button.Click += delegate 
            {
                _actionCommand.Execute(null);
            };
        }
    }

    private void TimerTick(object sender, object e)
    {
        if (TimerValue <= _timerInterval)
        {
            TimerValue += 0.5;
        }
        else
        {
            _timer.Stop();
            _timer.Tick -= TimerTick;
        }
    }

    private double _timerValue = 1;
    public double TimerValue
    {
        get => _timerValue;
        set
        {
            _timerValue = value;
            NotifyPropertyChanged(nameof(TimerValue));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

内容的提问来源于stack exchange,提问作者pnk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 02:53:17