首页 > 系统相关 >管理 Windows 实例的高效方法 —— 使用 WindowExtensions 类

管理 Windows 实例的高效方法 —— 使用 WindowExtensions 类

时间:2024-09-20 09:14:12浏览次数:1  
标签:savedLocations WindowExtensions 窗口 Windows previousLocation window 实例 windowType

管理 Windows 实例的高效方法 —— 使用 WindowExtensions

在现代的 Windows 应用程序开发中,尤其是使用 WPF(Windows Presentation Foundation)时,管理多个窗口实例是一个常见的需求。为了确保应用程序的用户体验流畅且一致,开发者常常需要控制窗口的创建、显示以及位置管理。本文将深入解析一个基于 C# 的 WindowExtensions 扩展类,实现单例化窗口、激活已有窗口以及保存窗口位置的高效方法。

目录

  1. 背景与需求
  2. 代码概述
  3. 详细解析
  4. 如何使用 WindowExtensions
  5. 优势与最佳实践
  6. 总结

背景与需求

在开发桌面应用程序时,常常需要管理多个不同类型的窗口。例如,应用程序可能包含主窗口、设置窗口、帮助窗口等。为了优化用户体验,通常希望:

  • 单例化窗口:确保每种类型的窗口在应用程序中只有一个实例,避免资源浪费和潜在的用户混淆。
  • 激活已有窗口:如果窗口已经打开,直接激活并置顶,而不是创建新的实例。
  • 保存窗口位置:当用户关闭窗口后,保存其位置,下次打开时恢复到上次的位置。

手动管理这些需求可能会导致重复代码和复杂的逻辑控制。因此,利用扩展方法和并发集合,可以简化这一过程。

代码概述

以下是 WindowExtensions 类的完整代码实现:

点击查看代码
/// <summary>
/// Windows 扩展类
/// </summary>
public static class WindowExtensions
{
    // 使用 ConcurrentDictionary 支持多种窗口类型
    private static readonly ConcurrentDictionary<Type, Window> _activeWindows = new ConcurrentDictionary<Type, Window>();
    // 保存关闭窗口位置
    private static readonly ConcurrentDictionary<Type, Point> _savedLocations = new ConcurrentDictionary<Type, Point>();

    /// <summary>
    /// 泛型方法,处理特定类型的窗口
    /// 单例化窗口,存在就激活
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="window"></param>
    public static void ShowActive<T>(this T window) where T : Window, new()
    {
        Application.Current.Dispatcher.Invoke(() =>
        {
            var windowType = typeof(T);
            var existingWindow = _activeWindows.GetOrAdd(windowType, _ => window);

            if (existingWindow.IsVisible)
            {
                if (existingWindow.WindowState == WindowState.Minimized)
                {
                    existingWindow.WindowState = WindowState.Normal;
                }
                existingWindow.Activate();
            }
            else
            {
                // 恢复窗口位置
                var previousLocation = _savedLocations.GetOrAdd(windowType, new Point(0, 0));
                if (previousLocation != default(Point))
                {
                    window.Left = previousLocation.X;
                    window.Top = previousLocation.Y;
                }
                _activeWindows[windowType] = window;
                window.Closed += (s, e) =>
                {
                    // 保存此类型窗口关闭的位置
                    _savedLocations[windowType] = new Point(window.Left, window.Top);
                    _activeWindows.TryRemove(windowType, out _);
                };

                window.Show();
            }
        });
    }
}

详细解析

让我们逐步拆解这段代码,了解其内部机制和实现逻辑。

使用 ConcurrentDictionary 管理窗口实例


// 使用 ConcurrentDictionary 支持多种窗口类型
private static readonly ConcurrentDictionary<Type, Window> _activeWindows = new ConcurrentDictionary<Type, Window>();
// 保存关闭窗口位置
private static readonly ConcurrentDictionary<Type, Point> _savedLocations = new ConcurrentDictionary<Type, Point>();

_activeWindows :用于存储当前活动的窗口实例。ConcurrentDictionary 确保在多线程环境下的线程安全。

_savedLocations :用于保存每种窗口类型关闭时的屏幕位置(左上角的坐标),以便下次打开时恢复。

泛型方法 ShowActive<T> 的实现

public static void ShowActive<T>(this T window) where T : Window, new()
{
    Application.Current.Dispatcher.Invoke(() =>
    {
        var windowType = typeof(T);
        var existingWindow = _activeWindows.GetOrAdd(windowType, _ => window);

        if (existingWindow.IsVisible)
        {
            if (existingWindow.WindowState == WindowState.Minimized)
            {
                existingWindow.WindowState = WindowState.Normal;
            }
            existingWindow.Activate();
        }
        else
        {
            // 恢复窗口位置
            var previousLocation = _savedLocations.GetOrAdd(windowType, new Point(0, 0));
            if (previousLocation != default(Point))
            {
                window.Left = previousLocation.X;
                window.Top = previousLocation.Y;
            }
            _activeWindows[windowType] = window;
            window.Closed += (s, e) =>
            {
                // 保存此类型窗口关闭的位置
                _savedLocations[windowType] = new Point(window.Left, window.Top);
                _activeWindows.TryRemove(windowType, out _);
            };

            window.Show();
        }
    });
}

关键点解析:

  1. 泛型约束:方法 ShowActive<T> 使用泛型,约束 T 必须继承自 Window 并且有无参数的构造函数(new())。

  2. 调度器调用:Application.Current.Dispatcher.Invoke 确保所有 UI 操作在主线程上执行,避免跨线程操作异常。

  3. 获取或添加窗口实例

  • GetOrAdd 方法尝试从 _activeWindows 中获取现有窗口实例。
  • 如果不存在,则添加传入的 window 实例。
  1. 窗口可见性判断
  • 如果窗口已可见,则激活并置顶。
  • 如果窗口未可见,则恢复上次保存的位置。
  1. 窗口关闭事件
  • 订阅窗口的 Closed 事件,在窗口关闭时保存位置并移除窗口实例。
  1. 显示窗口
  • 显示窗口。

窗口位置的保存与恢复

窗口位置的保存与恢复是 ShowActive<T> 方法的核心功能。

// 恢复窗口位置
var previousLocation = _savedLocations.GetOrAdd(windowType, new Point(0, 0));
if (previousLocation != default(Point))
{
    window.Left = previousLocation.X;
    window.Top = previousLocation.Y;
}
...
window.Closed += (s, e) =>
{
    // 保存此类型窗口关闭的位置
    _savedLocations[windowType] = new Point(window.Left, window.Top);
    _activeWindows.TryRemove(windowType, out _);
};

_savedLocations.GetOrAdd(windowType, new Point(0, 0)):尝试从 _savedLocations 中获取窗口类型对应的位置,如果不存在,则返回默认位置(左上角坐标为(0,0))。

window.Left = previousLocation.X;:设置窗口的左上角坐标 X。

window.Top = previousLocation.Y;:设置窗口的左上角坐标 Y。

// 保存此类型窗口关闭的位置
_savedLocations[windowType] = new Point(window.Left, window.Top);

_savedLocations[windowType] = new Point(window.Left, window.Top);:保存窗口关闭时的位置。

// 保存此类型窗口关闭的位置
_savedLocations[windowType] = new Point(window.Left, window.Top);

_activeWindows.TryRemove(windowType, out _);:移除窗口实例。

如何使用 WindowExtensions

在应用程序的各个窗口中,只需调用 ShowActive<T> 方法即可实现窗口的单例化、激活以及位置保存。

例如,在主窗口中:

// 假设有一个 SettingsWindow 类继承自 Window
var settingsWindow = new SettingsWindow();
settingsWindow.ShowActive();

在设置窗口中:

// 主窗口中的按钮点击事件
private void OpenSettings_Click(object sender, RoutedEventArgs e)
{
    var settingsWindow = new SettingsWindow();
    settingsWindow.ShowActive();
}

优势与最佳实践

  • 简化代码:利用扩展方法和并发集合,可以简化窗口管理的复杂逻辑。
  • 线程安全:使用 ConcurrentDictionary 保证线程安全。
  • 可扩展性:可以扩展支持更多窗口类型。
  • 代码可读性:代码结构清晰,命名符合规范。

总结

本文介绍了 WindowExtensions 类,它可以简化窗口管理的复杂逻辑,并提供单例化窗口、激活已有窗口以及保存窗口位置的高效方法。

标签:savedLocations,WindowExtensions,窗口,Windows,previousLocation,window,实例,windowType
From: https://www.cnblogs.com/lvyp1016520/p/18421812

相关文章

  • C# 报错:System.Threading.ThreadStateException:”当前线程不在单线程单元中,因此无法
    原因分析System.Threading.ThreadStateException 错误通常发生在尝试在非UI线程中创建或访问 ActiveX 控件(如COM 组件)时。在 Windows Forms应用程序中,所有 UI操作必须在创建该UI 的线程(通常是主线程)上执行。解决方案要解决这个问题,你需要确保在 UI 线程上创建......
  • 访问Github卡顿甚至进不去的解决办法(适用于Windows)
    本文首发自个人博客:点我查看一、前言Github是全球知名的开源宝库,但是对国内用户并不友好。当我们在浏览器中输入www.github.com时,如果你赶的时间点比较好可能会进去,但是大多数情况下浏览器不会对你的请求做出任何响应,就像下图这样:那么,有什么办法解决这个问题呢?二、访问Gith......
  • WPF System.Windows.Media.Color A value must be set, display ball and number in c
    privateColorGetRndColor(){Colorcr=newColor();cr.A=255;cr.R=(byte)(rnd.Next(0,255));cr.G=(byte)(rnd.Next(0,255));cr.B=(byte)(rnd.Next(0,255));returncr;}         //usercontrol.......
  • Windows 调试工具课程
    本文是我在集团内部上的课程记录而成的博客内容。在本次课程里面将和大家介绍一些在Windows上常用的调试工具,以及调查问题的常见套路。适合于伙伴们入门Windows调试本文以下内容是采用原本课程课件里面的一页页的内容组装而来,过程中补充一些讲课时的内容本次课程里面核心的......
  • C++入门基础知识76(实例)——实例 1【输出 “Hello, World!“】
    成长路上不孤单......
  • Windows 下 EGL PBuffer 测试代码
    Windows 上使用glad加载浏览器的LibEGL.dll 和LibGLESV2.dll,测试 EGL 在Windows 上的实现,代码:1#include<stdio.h>23#include"include/glad/egl.h"4#include"include/glad/gles3.2.h"56#defineSTB_IMAGE_WRITE_IMPLEMENTATION......
  • windows安装docker
    环境准备启用Hyper-V打开windows功能,找到Hyper-V并勾选,如果找不到Hyper-V新建txt,然后编辑内容pushd"%~dp0"dir/b%SystemRoot%\servicing\Packages\*Hyper-V*.mum>hyper-v.txtfor/f%%iin('findstr/i.hyper-v.txt2^>nul')dodism/online/norestart/add-p......
  • 修复Windows系统中mt6.dll文件缺失或损坏的问题——了解mt6.dll错误的原因及有效的解
    在使用Windows操作系统时,有时会遇到诸如“找不到mt6.dll”或“mt6.dll已损坏”等错误信息。这些问题可能会阻止应用程序的正常运行,给用户带来不便。本文将探讨这些问题的常见原因,并提供有效的解决方法,帮助用户快速恢复正常操作。原因分析文件缺失:用户可能无意中删除了mt6.......
  • Windows安装时调出系统的cmd功能 Shift+F10
    Windows安装时调出系统的cmd功能Shift+F10(笔记本可能是Shift+FN+F10)比如可以转换磁盘分区形式。 在Windows安装程序中同时按下【Shift+F10】键以打开命令提示符窗口,并按顺序输入以下命令。 diskpart listdisk(会显示磁盘列表) selectdisk1(1为要安装......
  • windows无法安装到这个磁盘,选中的磁盘采用gpt分区
    在安装Windows时,出现“windows无法安装到这个磁盘,选中的磁盘采用gpt分区”的错误提示,可以尝试两种解决方法:方法一,通过Diskpart工具将GPT转换为MBR;方法二,将引导模式更改为UEFI模式。以上是解决此问题的方法。摘要由作者通过智能技术生成有用有些用户反馈在安装Windows的过......