目录
- 一、前言
- 二、实现目标
- 1. 单例窗口实现
- 2. 父子窗口关联
- 三、代码实现
- 1.创建 WindowsingletonBase 封装单例逻辑
- 2.使用案例
- 2.1 无参构造窗体-使用单例窗体
- 2.2 有参构造窗体-使用单例窗体
- 2.3 有参构造窗体-窗体刷新
一、前言
在wpF企业级应用开发中,我们常常需要确保某个窗口在同一时间只能有一个实例存在,同时还需要支持窗口的关联关闭(关闭父窗体时,所有子窗体也会关闭)。
为了实现这些需求,我们采用一种侵入性较低的实现方式,通过创建一个通用的WindowSingletonBase
类来管理窗口的单例行为。
在这里,我们实现线程安全的单例窗口管理、完善的父子窗口生命周期控制以及灵活的参数化窗口构造,为WPF应用提供一套健壮的窗口管理解决方案。
二、实现目标
1. 单例窗口实现
- 支持无参和有参构造
- 通过
GetInstance()
方法获取或创建实例 - 窗口关闭时自动释放资源
2. 父子窗口关联
- 建立父子窗口链路关系
- 父窗口关闭时自动关闭所有子窗口
- 子窗口关闭时自动从父窗口的集合中移除
三、代码实现
1.创建 WindowSingletonBase 封装单例逻辑
通过泛型基类WindowSingletonBase<T>
封装单例逻辑,同时提供父子窗口管理功能,既保证了功能的完整性,又不会对业务窗口类造成过多约束。
using System; using System.Collections.Generic; using System.Linq; using System.Windows; namespace STC.Common.View.Component { /// <summary> /// 窗口单例基类,提供单例管理和父子窗口关联功能 /// </summary> /// <typeparam name="T">继承自Window的窗口类型</typeparam> public class WindowSingletonBase<T> where T : Window { // 线程安全锁 private static readonly object _lock = new object(); // 单例实例 private static T _instance; // 窗口构造方法 private static Func<object[], T> _constructor; // 窗口所拥有子窗口集合 private static readonly List<Window> _childwindows = new List<Window>(); /// <summary> /// 注册窗口构造函数 /// </summary> public static void RegisterConstructor(Func<object[], T> constructor) { lock (_lock) { _constructor = constructor; } } public static T Instance { get { return GetInstance(); } } /// <summary> /// 获取窗口单例实例 /// </summary> public static T GetInstance(params object[] args) { lock (_lock) { if (_instance == null || !_instance.IsLoaded) { if (_constructor == null) { throw new InvalidOperationException("can not found constructor"); } _instance = _constructor(args); } return _instance; } } /// <summary> /// 释放当前实例 /// </summary> public static void ReleaseInstance() { lock (_lock) { if (_instance != null) { _instance = null; } } } /// <summary> /// 添加子窗口并建立父子关系 /// </summary> public static void AddChildWindow(Window childWindow) { if (childWindow == null) throw new ArgumentNullExceppythontion(nameof(childWindow)); lock (_lock) { if (!_childWindows.Contains(childWindow)) { childWindow.Owner = _instance; // 设置父子关系 _childWindows.Add(childWindow); } } } /// <summary> /// 从子窗口集合中移除指定窗口 /// </summary> public static void RemoveChild(Window childWindow) { lock (_lock) { if (_childWindows.Contains(childWindow)) { _childWindows.Remove(childWindow); } } } /// <summary> /// 关闭所有子窗口 /// </summary> public static void CloseAllChildren() { lock (_lock) { foreach (var window in _childWindows.ToList()) // ToList避免修改android集合 { if (window != null) { window.Close();// 触编程客栈发子窗口的Closed事件 } } _childWindows.Clear(); } } /// <summary> /// 显示或激活窗口 /// </summary> public static void ShowOrActive() { if (_instance != null) { if (_instance.IsVisible) { _instance.Activate(); } else { _instance.Show(); } } } /// <summary> /// 关闭窗口 /// </summary> public static void CloseWindow() { if (_instance != null) { if (_instance.IsVisible) { _instance.Close(); } } } } }
2.使用案例
在步骤1中,创建了WindowSingletonBase用来管理单例窗口。现在我们来使用WindowSingletonBase。
在需要单例运行的窗体中,做三件事:
- 1.注册构造函数。
- 2.创建实例
- 3.重写OnClose方法(用于释放资源)
2.1 无参构造窗体-使用单例窗体
ParentWindow.cs
public partial class ParentWindow : Window { static ParentWindow() { // 注册无参构造函数 WindowSingletonBase<ParentWindow>.RegisterConstructor(args => new ParentWindow()); } public ParentWindow() { InitializeComponent(); } /// <summary> /// 声明单例窗口 Instance /// </summary> public static ParentWindow CreateInstance() { return WindowSingletonBase<ParentWindow>.GetInstance(); } protected override void OnClosed(EventArgs e) { base.OnClosed(e); // 释放单例实例并关闭所有子窗口 WinjavascriptdowSingletonBase<ParentWindow>.ReleaseInstance(); WindowSingletonBase<ParentWindow>.CloseAllChildren()编程客栈; } private void OpenChildWindow(object sender, RoutedEventArgs e) { // 获取子窗口实例并显示 var childWindow = ChildWindow.CreateInstance(); WindowSingletonBase<ParentWindow>.AddChildWindow(childWindow); WindowSingletonBase<ChildWindow>.ShowOrActivate(); } }
ChildWindow.cs
public partial class ChildWindow : Window { static ChildWindow() { // 注册无参构造函数(方式1) // WindowSingletonBase<ChildWindow>.RegisterConstructor(args => new ChildWindow()); // 注册无参构造函数(方式2) WindowSingletonBase<ChildWindow>.RegisterConstructor(delegate (object[] args) { return new ChildWindow(); }); } public ChildWindow() { InitializeComponent(); } /// <summary> /// 声明单例窗口 /// </summary> public static ChildWindow CreateInstance() { return WindowSingletonBase<ChildWindow>.GetInstance(); } /// <summary> /// 关闭窗口 /// </summary> protected override void OnClosed(EventArgs e) { base.OnClosed(e); // 从父窗体的子窗口列表中移除 WindowSingletonBase<ParentWindow>.RemoveChild(this); WindowSingletonBase<ChildWindow>.ReleaseInstance(); } }
2.2 有参构造窗体-使用单例窗体
ParentWindow.cs
public partial class ParentWindow : Window { static ParentWindow() { // 注册无参构造函数 WindowSingletonBase<ParentWindow>.RegisterConstructor(args => new ParentWindow()); } public ParentWindow() { InitializeComponent(); } /// <summary> /// 声明单例窗口 Instance /// </summary> public static ParentWindow CreateInstance() { return WindowSingletonBase<ParentWindow>.GetInstance(); } protected override void OnClosed(EventArgs e) { base.OnClosed(e); // 释放单例实例并关闭所有子窗口 WindowSingletonBase<ParentWindow>.ReleaseInstance(); WindowSingletonBase<ParentWindow>.CloseAllChildren(); } private void OpenChildWindow(object sender, RoutedEventArgs e) { // 获取子窗口实例并显示 var childWindow = ChildWindow.CreateInstance("张三", 18); WindowSingletonBase<ParentWindow>.AddChildWindow(childWindow); WindowSingletonBase<ChildWindow>.ShowOrActivate(); } }
ChildWindow.cs
public partial class ChildWindow : Window { static ChildWindow() { // 注册无参构造函数 WindowSingletonBase<ChildWindow>.RegisterConstructor(delegate (object[] args) { return new AddGroupWin(args[0] as string, (int)args[1]); }); } public ChildWindow(string name, int age) { InitializeComponent(); } /// <summary> /// 声明单例窗口 /// </summary> public static ChildWindow CreateInstance(string name, int age) { return WindowSingletonBase<ChildWindow>.GetInstance(name, age); } /// <summary> /// 关闭窗口 /// </summary> protected override void OnClosed(EventArgs e) { base.OnClosed(e); // 从父窗体的子窗口列表中移除 WindowSingletonBase<ParentWindow>.RemoveChild(this); WindowSingletonBase<ChildWindow>.ReleaseInstance(); } }
2.3 有参构造窗体-窗体刷新
如果这个弹窗是在列表中,点击编辑按钮弹窗,我们需要每次点击的时候都刷新窗口。可以在CreateInstance方法中做一些改变。
ParentWindow.cs
public partial class ParentWindow : Window { static ParentWindow() { // 注册无参构造函数 WindowSingletonBase<ParentWindow>.RegisterConstructor(args => new ParentWindow()); } public ParentWindow() { InitializeComponent(); } /// <summary> /// 声明单例窗口 Instance /// </summary> public static ParentWindow CreateInstance() { return WindowSingletonBase<ParentWindow>.GetInstance(); } protected override void OnClosed(EventArgs e) { base.OnClosed(e); // 释放单例实例并关闭所有子窗口 WindowSingletonBase<ParentWindow>.ReleaseInstance(); WindowSingletonBase<ParentWindow>.CloseAllChildren(); } private void OpenChildWindow(object sender, RoutedEventArgs e) { // 获取子窗口实例并显示 var childWindow = ChildWindow.CreateInstance("张三", 18); WindowSingletonBase<ParentWindow>.AddChildWindow(childWindow); WindowSingletonBase<ChildWindow>.ShowOrActivate(); } }
ChildWindow.cs
public partial class ChildWindow : Window { // 演示需要(不推荐在ChildWindow中声明viewModel) private ChildWindowViewModel viewModel; private static ChildWindow _childWindow; static ChildWindow() { // 注册无参构造函数 WindowSingletonBase<ChildWindow>.RegisterConstructor(delegate (object[] args) { return new AddGroupWin(args[0] as string, (int)args[1]); }); } public ChildWindow(string name, int age) { InitializeComponent(); } /// <summary> /// 声明单例窗口 /// </summary> public static ChildWindow CreateInstance(string name, int age) { if (_childWindow!=null) { ChildWindowWinViewModel model = _childWindow.viewModel as ChildWindowWinViewModel; // 点击的是当前展示的数据,则返回当前window if (model != null && model.name == name && model.age == age) { return _childWindow; } else { // 点击的是另一条数据,则重新new viewModel,重新设置 _childWindow的DataContext // 在这里省略ChildWindowWinViewModel代码,根据情况自行编写 _childWindow.viewModel = new ChildWindowWinViewModel(id, instId, _childWindow); _childWindow.DataContext = _childWindow.viewModel; return _childWindow; } } // 如果 _childWindow 是空的,则声明单例窗口。 _childWindow = WindowSingletonBase<ChildWindow>.GetInstance(name, age); return _childWindow; } /// <summary> /// 关闭窗口 /// </summary> protected override void OnClosed(EventArgs e) { base.OnClosed(e); // 从父窗体的子窗口列表中移除 WindowSingletonBase<ParentWindow>.RemoveChild(this); WindowSingletonBase<ChildWindow>.ReleaseInstance(); } }
以上就是WPF中实现单例窗口的解决方案的详细内容,更多关于WPF单例窗口的资料请关注编程客栈(www.devze.com)其它相关文章!
精彩评论