首页 > 其他分享 >.Net实现深色模式窗口

.Net实现深色模式窗口

时间:2023-10-15 09:56:36浏览次数:24  
标签:深色 窗口 dark ui obj new static Net ListView

深色模式窗口实现原理是遍历窗口的所有子控件,将子控件的字体颜色和背景色修改为深色模式,代码为:

public static void darkSubs(Control ui)
        {
            foreach (var obj in ui.Controls)
            {
                if (obj is Button btn)
                    dark(btn);
                else if (obj is TextBoxBase tx)
                    dark(tx);
                else if (obj is ListBox lb)
                    dark(lb);
                else if (obj is TreeView tr)
                    dark(tr);
                else if (obj is ListView lv)
                    dark(lv);
                else if (obj is ToolStrip tb)
                    dark(tb);
                else if (obj is PropertyGrid pg)
                    dark(pg);
                else if (obj is Panel panel)
                    darkSubs(panel);
                else if (obj is UserControl uc)
                    darkSubs(uc);
            }
        }

如果子窗口是Panel或者UserControl,则通过递归调用darkSubs,修改其子控件为深色模式。

对于普通控件,一般只需要修改字体颜色和背景色,即可实现深色模式,如TreeView:

public static void dark(TreeView ui)
        {
            ui.BackColor = CONTROL_BACK;
            ui.ForeColor = TEXT_FORE;
            ui.BorderStyle = FRAME_BORDER;
        }

对于ListView控件,当其处于Detail显示模式时,由于其表头Header不能直接修改背景颜色,需要自定义表头绘制方法:

public static void dark(ListView ui)
        {
            ui.BackColor = CONTROL_BACK;
            ui.ForeColor = TEXT_FORE;
            ui.BorderStyle = FRAME_BORDER;

            ui.OwnerDraw = true;
            ui.DrawItem += Ui_DrawItem;
            ui.DrawColumnHeader += ListView_DrawColumnHeader;
            ui.ColumnWidthChanged += ListView_ColumnWidthChanged;
            //ui.LostFocus += (s,e) => ui.autoSpan();
            ui.GotFocus += (s, e) => ui.autoSpan();
            ui.autoSpan();
        }

        private static void ListView_ColumnWidthChanged(object sender, ColumnWidthChangedEventArgs e)
        {
            var ui = sender as ListView;
            if (e.ColumnIndex == ui.Columns.Count - 1)
                return;
            var col = ui.Columns[ui.Columns.Count - 1];
            col.Width = -2;
        }

        private static void ListView_DrawColumnHeader(object sender, DrawListViewColumnHeaderEventArgs e)
        {
            //Fills one solid background for each cell.
            using (SolidBrush backBrush = new SolidBrush(FORM_BACK))
            {
                e.Graphics.FillRectangle(backBrush, e.Bounds);
            }
            //Draw the borders for the header around each cell.
            using (Pen backBrush = new Pen(CONTROL_BACK))
            {
                e.Graphics.DrawRectangle(backBrush, e.Bounds);
            }
            using (SolidBrush foreBrush = new SolidBrush(TEXT_FORE))
            {
                //Since e.Header.TextAlign returns 'HorizontalAlignment' with values of (Right, Center, Left).  
                //DrawString uses 'StringAlignment' with values of (Near, Center, Far). 
                //We must translate these and setup a vertical alignment that doesn't exist in DrawListViewColumnHeaderEventArgs.
                StringFormat stringFormat = GetStringFormat(e.Header.TextAlign);

                //Do some padding, since these draws right up next to the border for Left/Near.  Will need to change this if you use Right/Far
                Rectangle rect = e.Bounds; rect.X += 2;
                // e.Graphics.DrawString(e.Header.Text, e.Font, foreBrush, rect, stringFormat);
                e.Graphics.DrawString(e.Header.Text, e.Font, foreBrush, rect, stringFormat);
            }
        }

        private static StringFormat GetStringFormat(HorizontalAlignment ha)
        {
            StringAlignment align;

            switch (ha)
            {
                case HorizontalAlignment.Right:
                    align = StringAlignment.Far;
                    break;
                case HorizontalAlignment.Center:
                    align = StringAlignment.Center;
                    break;
                default:
                    align = StringAlignment.Near;
                    break;
            }

            return new StringFormat()
            {
                Alignment = align,
                LineAlignment = StringAlignment.Center
            };
        }

        private static void Ui_DrawItem(object sender, DrawListViewItemEventArgs e)
        {
            e.DrawDefault = true;
        }

对于Form的标题栏,也无法通过属性直接设置背景颜色,但是在Win10及以上版本的最新补丁中,有OS Api可以修改窗口标题栏颜色模式,所以直接调用OS Api实现:

[DllImport("DwmApi")]
        private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, int[] attrValue, int attrSize);

        public static void setDarkTitle(Form form)
        {
            IntPtr hwnd = form.Handle;
            //DwmSetWindowAttribute(hwnd, 19, new[] { 1 }, 4);
            //DwmSetWindowAttribute(hwnd, 20, new[] { 1 }, 4);
            if (DwmSetWindowAttribute(hwnd, 19, new[] { 1 }, 4) != 0)
                DwmSetWindowAttribute(hwnd, 20, new[] { 1 }, 4);
        }

为了方便应用调用,通过C#的静态扩展方法的方式,封装Form的扩展方法:

public static T dark<T>(this T form) where T : Form
        {
            setDarkTitle(form);
            form.BackColor = FORM_BACK;
            form.ForeColor = TEXT_FORE;

            darkSubs(form);

            return form;
        }

应用程序只要简单调用dark方法,即可实现窗口的深色模式显示:

var myForm = new MyForm().dark();
myForm.Show();

深色模式效果图如下:

 Github完整代码:https://github.com/bsmith-zhao/vfs/blob/main/util/ext/DarkFormEx.cs

标签:深色,窗口,dark,ui,obj,new,static,Net,ListView
From: https://www.cnblogs.com/bsmith/p/17765281.html

相关文章

  • 使用Docker buildx 为 .NET 构建多平台镜像
    .NET团队有一篇博客改进多平台容器支持,详细介绍了.NET7以上的平台可以轻松的使用Dockerbuildx工具构建多平台的镜像。buildx是Docker官方提供的一个构建工具,它可以帮助用户快速、高效地构建Docker镜像,并支持多种平台的构建。使用buildx,用户可以在单个命令中构建多......
  • 【科研03】【代码复现】TransUnet道路提取
    目录1.数据准备dataprocess2.文件更名filesrename2.1.数据更名npzrename2.2.文档更名txtrename3.代码修改codechange3.1.目录调整contents3.2.数据读取code13.2.训练参数parameterset3.2.1.目标类别numclasses3.2.2.运行轮次maxepochs3.2.3.批次传入......
  • 【科研02】【代码复现】【代码分享】TransUnet-RoadExtract 道路提取【数据预处理-ras
    目录1.数据处理dataprocess1.1.类型转换RastertoPng1.2.边缘填充Resize1.2.1.填充Resizeimage1.2.1.填充Resizelabel1.3.批量裁剪Clip1.4.波段缩减3bandsto1band1.5.筛选图像Choose1.6.转换格式Transformtonpz1.7.读取列表ReadFilesToList1.数......
  • 【科研01】【代码复现】TransUnet-文件目录安排
    目录1.信息TransUnet1.1.时间opentime1.2.链接Linkgithub1.3.应用Use2.自用TransUnet2.1.目录Tree2.2.修改Change1.信息TransUnet1.1.时间opentime20211.2.链接Linkgithubhttps://github.com/Beckschen/TransUNet1.3.应用Use  本是应用于......
  • 论文阅读:CurveNet: Curvature-Based Multitask Learning Deep Networks for 3D Object
    CurveNet:Curvature-BasedMultitaskLearningDeepNetworksfor3DObjectRecognitionCurveNet:用于3D对象识别的基于曲率的多任务学习深度网络IEEE2021摘要:在计算机视觉领域,3D对象识别是许多实际应用中最重要的任务之一。三维卷积神经网络(CNN)已经在3D物体识别中展示了其......
  • lesson12-窗口监听事件
      packagecom.zym.lesson12;importjavax.swing.*;importjava.awt.*;importjava.awt.event.WindowAdapter;importjava.awt.event.WindowEvent;publicclassTestWindowListener{publicstaticvoidmain(String[]args){newWinFrame("less......
  • .NET 5 Web API 中JWT详细教程:保护你的Web应用
    第一部分:理解JWTJSONWebToken(JWT)是一种在不同系统之间传递信息的安全方式。它由三部分组成:头部(Header)、载荷(Payload)和签名(Signature)。头部包含加密算法和令牌类型等信息,载荷包含用户的信息,签名用于验证令牌的真实性。安装必要的包在开始之前,我们需要在你的项目中添加一些必要的Nu......
  • 【科研00】【论文阅读】【略读笔记】TransUnet
    目录0.引言1.链接Link2.阅读Read2.1.结构Structure2.2.编码Encoder2.2.1.卷积CNN2.2.2.变换Transformer2.3.解码Decoder3.优势Advantage4.想法Think0.引言  想尝试TransUnet,先稍微的了解了一下结构。  如果阅读到这篇文章,请略过,本文仅是个人的随笔。......
  • asp.net 分片下载
    参考:https://learn.microsoft.com/en-us/answers/questions/726990/serving-video-file-stream-from-asp-net-core-6-minihttps://khalidabuhakmeh.com/partial-range-http-requests-with-aspnet-core HTTPRangeRequestsandPartialResponsesWithASP.NETCoreLongg......
  • Netty源码编译
    Netty源码编译想了解Netty源码,最好先从netty-example开始,多跑几个example,了解Netty的实际应用。编译netty-example会出现很多乱七八糟的问题,根本原因是因为缺少io.netty.util.collection包。解决方法1.先installDev-Tools模块2.接着installCommon模块instal......