当前位置: 首页 > news >正文

wpf 实现窗口点击关闭按钮时 ​​隐藏​​ 而不是真正关闭,并且只有当 ​​父窗口关闭时才真正退出​​ 、父子窗口顺序控制与资源安全释放​

文章目录

    • 实现方法
      • **方法 :重写 `OnClosing` 方法**
        • **子窗口(SettingView)代码**
        • **父窗口(MainWindow)代码**
      • **关键点**
      • **适用场景**
    • 为什么if (Owner == null || !Owner.IsLoaded)能够判断父窗口已经关闭
      • **1. `Owner == null` 检查**
      • **2. `!Owner.IsLoaded` 检查**
      • **为什么 `Owner` 不会自动置 `null`?**
      • **正确的判断逻辑**
      • **特殊情况**
      • **总结**
    • 应用程序退出会自动关闭所有窗口吗,怎么知道先关父窗口还是先关子窗口呢
    • **1. 应用程序退出时,所有窗口会自动关闭吗?**
    • **2. 如何知道先关闭父窗口还是子窗口?**
      • **验证示例**
    • **3. 如何控制关闭顺序?**
      • **方法 1:手动管理关闭顺序**
      • **方法 2:阻止子窗口自动关闭**
    • **4. 关键总结**
    • **5. 最佳实践**

实现方法

在 WPF 中,如果希望窗口点击关闭按钮时 隐藏 而不是真正关闭,并且只有当 父窗口关闭时才真正退出,可以通过以下方式实现:


方法 :重写 OnClosing 方法

在子窗口(SettingView)中重写 OnClosing,判断是否由父窗口触发关闭,如果不是则取消关闭并隐藏窗口。

子窗口(SettingView)代码
public partial class SettingView : Window
{public SettingView(){InitializeComponent();}protected override void OnClosing(CancelEventArgs e){// 如果父窗口正在关闭,则允许子窗口关闭if (Owner == null || !Owner.IsLoaded){base.OnClosing(e);return;}// 否则隐藏窗口,并取消关闭操作e.Cancel = true;this.Hide();}
}
父窗口(MainWindow)代码
public partial class MainWindow : Window
{private SettingView _settingView;public MainWindow(){InitializeComponent();_settingView = new SettingView { Owner = this };}private void ShowSettingView_Click(object sender, RoutedEventArgs e){_settingView.Show(); // 显示窗口(如果已隐藏)}protected override void OnClosed(EventArgs e){base.OnClosed(e);_settingView.Close(); // 父窗口关闭时,真正关闭子窗口}
}

关键点

  1. Owner 属性:子窗口必须设置 Owner = this(父窗口),否则无法判断父窗口是否关闭。
  2. IsLoaded 检查:确保父窗口仍然存在,避免 NullReferenceException
  3. Hide() 代替 Close():点击关闭按钮时隐藏窗口,而不是销毁。
  4. 父窗口关闭时真正关闭子窗口:在父窗口的 OnClosed 中调用 Close()

适用场景

  • 设置窗口:点击关闭按钮时隐藏,下次打开时恢复状态。
  • 工具窗口:不希望频繁创建和销毁窗口,提高性能。
  • 模态对话框:保持数据状态,直到父窗口关闭。

为什么if (Owner == null || !Owner.IsLoaded)能够判断父窗口已经关闭

1. Owner == null 检查

  • Owner 是 WPF 窗口的一个属性,表示当前窗口的父窗口。
  • 如果 父窗口从未被设置(即 Owner 从未赋值),则 Owner == nulltrue
  • 如果 父窗口已被关闭,WPF 不会自动将 Owner 设为 null,所以 Owner == null 通常不会为 true(除非手动置空)。

结论Owner == null 主要用于检测 是否从未设置父窗口,而不是检测父窗口是否关闭。


2. !Owner.IsLoaded 检查

  • IsLoaded 是 WPF 窗口的一个属性,表示窗口是否已经加载并显示。
  • 父窗口关闭时,它的 IsLoaded 会变为 false(即使 Owner 仍然指向它)。
  • 因此,!Owner.IsLoaded 可以判断 父窗口是否已关闭

结论!Owner.IsLoaded 是检测父窗口是否关闭的关键条件。


为什么 Owner 不会自动置 null

  • WPF 的 Owner 属性是一个 弱引用(Weak Reference),它不会阻止垃圾回收(GC)。
  • 父窗口关闭后Owner 仍然会保留对它的引用(只是 IsLoaded 变为 false)。
  • 如果父窗口被垃圾回收,Owner 也不会自动变成 null(除非手动赋值 Owner = null)。

正确的判断逻辑

if (Owner == null || !Owner.IsLoaded)
{// 情况1:从未设置父窗口(Owner == null)// 情况2:父窗口已关闭(!Owner.IsLoaded)base.OnClosing(e); // 允许关闭
}
else
{e.Cancel = true;  // 取消关闭this.Hide();      // 隐藏窗口
}

特殊情况

  1. 如果父窗口从未设置(Owner == null
    • 子窗口会直接关闭(因为没有父窗口需要等待)。
  2. 如果父窗口已关闭(!Owner.IsLoaded
    • 子窗口也会关闭(因为父窗口已经不存在了)。
  3. 如果父窗口仍然存在(Owner != null && Owner.IsLoaded
    • 子窗口会隐藏(Hide()),而不是关闭。

总结

条件含义
Owner == null从未设置父窗口
!Owner.IsLoaded父窗口已关闭(或未加载)
!Owner.IsVisible父窗口不可见(可能是最小化或隐藏)
!Owner.IsActive父窗口未激活(不是当前焦点窗口)

if (Owner == null || !Owner.IsLoaded) 是一个 合理且安全 的方式来判断父窗口是否关闭。 ✅


应用程序退出会自动关闭所有窗口吗,怎么知道先关父窗口还是先关子窗口呢

在 WPF 中,窗口关闭顺序和应用程序退出的行为取决于 窗口的所有权关系(Owner关闭逻辑。以下是关键问题的解答:


1. 应用程序退出时,所有窗口会自动关闭吗?

是的,但取决于关闭方式:

  • 正常关闭(Application.Current.Shutdown()
    所有窗口(包括隐藏的)会按 反向顺序 关闭(子窗口先关闭,父窗口后关闭)。
  • 强制关闭(Environment.Exit(0) 或进程终止)
    所有窗口 立即销毁,不触发 Closing 事件。

2. 如何知道先关闭父窗口还是子窗口?

WPF 的窗口关闭顺序遵循 从子到父 的规则:

  1. 子窗口先关闭(如果设置了 Owner)。
  2. 父窗口后关闭

验证示例

// 父窗口(MainWindow)
public partial class MainWindow : Window
{public MainWindow(){InitializeComponent();var childWindow = new ChildWindow { Owner = this };childWindow.Show();}protected override void OnClosing(CancelEventArgs e){Console.WriteLine("父窗口正在关闭");base.OnClosing(e);}
}// 子窗口(ChildWindow)
public partial class ChildWindow : Window
{protected override void OnClosing(CancelEventArgs e){Console.WriteLine("子窗口正在关闭");base.OnClosing(e);}
}

输出

子窗口正在关闭
父窗口正在关闭

👉 结论:子窗口先关闭,父窗口后关闭。


3. 如何控制关闭顺序?

方法 1:手动管理关闭顺序

如果希望 父窗口关闭时,子窗口才关闭(而不是相反),可以:

// 父窗口(MainWindow)
protected override void OnClosing(CancelEventArgs e)
{// 先关闭所有子窗口foreach (Window window in OwnedWindows){window.Close();}base.OnClosing(e);
}

方法 2:阻止子窗口自动关闭

如果希望 子窗口在父窗口关闭时保持存活(例如隐藏而非关闭):

// 子窗口(ChildWindow)
protected override void OnClosing(CancelEventArgs e)
{if (Owner != null && Owner.IsVisible){e.Cancel = true;  // 取消关闭this.Hide();      // 隐藏窗口}else{base.OnClosing(e); // 父窗口已关闭,允许子窗口关闭}
}

4. 关键总结

行为说明
默认关闭顺序子窗口 → 父窗口(反向依赖顺序)
Owner 的作用决定窗口的父子关系,影响关闭顺序
Application.Current.Shutdown()触发所有窗口按顺序关闭
Environment.Exit(0)强制终止,不触发 Closing 事件
隐藏窗口是否影响关闭?隐藏的窗口仍然会被关闭,除非手动取消 Closing

5. 最佳实践

  • 如果子窗口需要存活(如工具窗口):
    • Closing 事件中 Hide() + e.Cancel = true
  • 如果子窗口必须随父窗口关闭
    • 让 WPF 自动处理(默认行为)。
  • 如果需要自定义关闭顺序
    • 在父窗口 OnClosing 中手动关闭子窗口。

这样就能精准控制 WPF 窗口的关闭逻辑! 🚀

http://www.dtcms.com/a/279812.html

相关文章:

  • AI 优化大前端动画性能:流畅性与资源消耗的平衡
  • Django REST framework 源码剖析-URL地址详解(Returning URLs)
  • 亚马逊广告进阶玩法:如何巧妙利用ASIN广告优化产品排名
  • Java面试总结(经典题)(Java多线程)(一)
  • 数据结构——优先队列(priority_queue)的巧妙运用
  • 排序树与无序树:数据结构中的有序性探秘
  • K8s存储系统(通俗易懂版)
  • 约束|additional
  • 如何更改Blender插件安装位置呢?
  • 【Vue】Vue3.6 - Vapor 无虚拟DOM
  • 算法:投票法
  • 硬盘爆满不够用?这个免费神器帮你找回50GB硬盘空间
  • SpringBoot 整合 MyBatis-Plus
  • 多线程是如何保证数据一致和MESI缓存一致性协议
  • 深入浅出Kafka Broker源码解析(下篇):副本机制与控制器
  • Open3D 点云DBSCAN密度聚类
  • 鹧鸪云重构光伏发电量预测的精度标准
  • JS解密大麦网分析
  • 06【C++ 初阶】类和对象(上篇) --- 初步理解/使用类
  • 创客匠人谈创始人 IP 打造:打破自我认知,方能筑牢 IP 变现根基
  • linux下的消息队列数据收发
  • python学智能算法(十七)|SVM基础概念-向量的值和方向
  • 计算实在论:一个关于存在、认知与时间的统一理论
  • win7+Qt1.12.3+opencv4.3+mingw32+CMake3.15编译libopencv_world430.dll过程
  • 【Python】-实用技巧5- 如何使用Python处理文件和目录
  • Java并发编程之事务管理详解
  • Redis集群方案——Redis分片集群
  • GPU集群运维
  • Unity物理系统由浅入深第六节:高级主题与前沿探索
  • 动态规划题解——乘积最大子数组【LeetCode】