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.tpcf.cn/bicheng/89362.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

硬件设计学习DAY4——电源完整性设计:从概念到实战

每日更新教程,评论区答疑解惑,小白也能变大神!" 目录 一.电源完整性 1.1电源完整性的核心概念 1.2电源完整性的三个关键目标 1.3地弹现象的通俗解释 1.4总结要点 二.电源分配网络(PDN)的作用 电源与GND网络…

QT跨平台应用程序开发框架(8)—— 多元素控件

目录 一,关于多元素控件 二,QListWidget 2.1 主要方法 2.2 实现新增删除 三,Table Widget 3.1 主要方法 3.2 代码演示 四,Tree Widget 4.1 主要方法 4.2 代码演示 一,关于多元素控件 多元素控件就是一个控件里面包含了…

【React Native】环境变量和封装 fetch

环境变量和封装fetch 环境变量 一般做开发,都会将接口地址配置到环境变量里。在Expo建的项目里,也可以使用环境变量。 在项目根目录新建一个.env文件,里面添加上: EXPO_PUBLIC_API_URLhttp://localhost:3000如果你用手机真机等…

Linux 基础命令详解:从入门到实践(1)

Linux 基础命令详解:从入门到实践(1) 前言 在 Linux 操作系统中,命令行是高效管理系统、操作文件的核心工具。无论是开发者、运维工程师还是Linux爱好者,掌握基础命令都是入门的第一步。本文将围绕Linux命令的结构和常…

基于 SpringBoot+VueJS 的私人牙科诊所管理系统设计与实现

基于 SpringBootVueJS 的私人牙科诊所管理系统设计与实现摘要随着人们对口腔健康重视程度的不断提高,私人牙科诊所的数量日益增多,对诊所管理的信息化需求也越来越迫切。本文设计并实现了一个基于 SpringBoot 和 VueJS 的私人牙科诊所管理系统&#xff0…

华为云Flexus+DeepSeek征文|体验华为云ModelArts快速搭建Dify-LLM应用开发平台并创建天气预报大模型

华为云FlexusDeepSeek征文|体验华为云ModelArts快速搭建Dify-LLM应用开发平台并创建天气预报大模型 什么是华为云ModelArts 华为云ModelArts ModelArts是华为云提供的全流程AI开发平台,覆盖从数据准备到模型部署的全生命周期管理,帮助企业和开…

Mysql系列--0、数据库基础

目录 一、概念 1.1什么是数据库 1.2什么是mysql 1.3登录mysql 1.4主流数据库 二、Mysql与数据库 三、Mysql架构 四、SQL分类 五、存储引擎 5.1概念 5.2查看引擎 5.3存储引擎对比 一、概念 1.1什么是数据库 由于文件保存数据存在文件的安全性问题 文件不利于数据查询和管理…

深度学习和神经网络的介绍

一.前言本期不涉及任何代码,本专栏刚开始和大家介绍了一下机器学习,而本期就是大家介绍一下深度学习还有神经网络,作为一个了解就好。二.深度学习2.1 什么是深度学习?在介绍深度学习之前,我们先看下⼈⼯智能&#xff0…

AI驱动的软件工程(下):AI辅助的质检与交付

📚 系列文章导航 AI驱动的软件工程(上):人机协同的设计与建模 AI驱动的软件工程(中):文档驱动的编码与执行 AI驱动的软件工程(下):AI辅助的质检与交付 大家好…

【WRFDA实操第一期】服务器中安装 WRFPLUS 和 WRFDA

目录在服务器上下载并解压 WRF v4.6.1编译 WRFDA 及相关库安装和配置所需库安装 WRFPLUS 和 WRFDA 以运行 4DVAR 数据同化一、安装 WRFPLUS(适用于 WRF v4.0 及以上版本)二、安装 WRFDA(用于 4DVAR)WRFDA 和 WRFPLUS 的安装说明另…

【机器学习【6】】数据理解:数据导入、数据审查与数据可视化方法论

文章目录一、机器学习数据导入1、 Pandas:机器学习数据导入的最佳选择2、与其他方法的差异二、机器学习数据理解的系统化方法论1、数据审查方法论:六维数据画像技术维度1:数据结构审查维度2:数据质量检查维度3:目标变量…

AI炼丹日志-30-新发布【1T 万亿】参数量大模型!Kimi‑K2开源大模型解读与实践

点一下关注吧!!!非常感谢!!持续更新!!! 🚀 AI篇持续更新中!(长期更新) AI炼丹日志-29 - 字节跳动 DeerFlow 深度研究框斜体样式架 私…

如何关闭Elasticsearch的安全认证的解决方法

在Elasticsearch 中,启动之后,需要输入用户名和密码,才可以访问,在测试环境中,很不方便,本章教程,主要介绍如何关闭Elasticsearch 的安全认证。在 Elasticsearch 8.x / 9.x 中,默认是…

day051-ansible循环、判断与jinja2模板

文章目录0. 老男孩思想-男女性需求差异1. 手动指定客户机密码2. 批量更新主机名2.1 hostname模块2.2 添加主机清单变量2.3 编写批量修改主机名剧本2.4 修改hosts文件2.5 分发hosts文件剧本3. ansible的并行进程数4. 分组设置主机密码-主机清单分组变量5. 案例:ansib…

大模型安全建设:破误区、识风险、筑防线20250714

🔐 大模型安全建设:破误区、识风险、筑防线作者:Narutolxy|编辑时间:2025年7月在负责公司 AI 产品落地的过程中,一度以为只要选用主流开源大模型,前面加一层“敏感词提示词过滤”,就…

fastadmin中ajax弹窗修改文字为英文

需要把上图的中文改为 切换语言自动切换成英文找到这个文件public/assets/js/backend.js找到如下图部分 // //点击包含.btn-ajax的元素时发送Ajax请求 原页面// $(document).on(click, .btn-ajax,.ajaxit, function (e) {// var that this;// var options $.exte…

大型语言模型(LLM)的技术面试题

大型语言模型(LLM)的技术面试题 目录 大型语言模型(LLM)的技术面试题 一、提示校准:减轻提示学习中的偏见 二、矢量存储的适用场景 三、模型与人类价值观对齐的技术 四、RLHF中的Reward Hacking 五、微调效果的关键影响因素:预训练模型架构与大小 六、Transformer自注意力…

数字IC后端培训教程之数字IC后端项目典型问题解析

今天给大家分享下最近几个典型的数字后端项目案例,希望对大家的学习和工作有所帮助。 数字IC后端培训教程之数字后端项目典型项目案例解析 Q1:星主,有啥办法可以看到refinePlace或者ecoPlace都动到了那些inst吗,log里只会有mean和max move&…

网络(数据库1)

常用数据库: 1.关系型数据库: 将复杂的数据结构简化为二维表格形式 大型:0racle、DB2 中型:MySq1、sQLServer 小型:Sqlite 2.非关系型数据库以键值对存储,且结构不固定。//JSON Redis MongoDB数据存储:变量、数组、链表 内存 &…

6.删除-demo

在连接数据库的基础上deleteResult, err : db.Exec("DELETE FROM user0 WHERE id ?", 1)package main//删除-demoimport ("database/sql""fmt"_ "github.com/go-sql-driver/mysql""log" )func main() {db, err : sql.Open…