[DForm]我也来做自定义Winform之另类标题栏重绘
引用:https://www.cnblogs.com/encoding/p/5603080.html
其他下载:https://github.com/dongger/MomoForm
据说得有楔子
按照惯例,先来几张样例图(注:为了展示窗口阴影效果,截图范围向外扩展了些,各位凭想象吧)。
还要来个序
其实,很多年没写过Winform了,前端时间在重构我们公司自己的呼叫中心系统,突然就觉得客户端好丑好丑,对于我这种强迫症晚期患者来说,界面不好看都不知道怎么写代码的,简直就是种折磨,还是满清十大酷刑级别那种。
很多人推荐WPF,不过个人对WPF没啥感觉,而且据说也无法支持2.0,还是采用Winform技术来搞吧。
终于第一节
做Winform皮肤,我了解的无非有2种方式。
1.采用纯图片模式:由专业美工设计各种样式的图片,进行窗口背景图片设置
2.采用GDI+纯代码绘制:参照美工设计的各种样式的图片,使用C#代码绘制出来
第一种方式很简单,但是可复用性不高,性能上面应该也会有一些影响,如果图片太大,窗口拖动等引起的重绘时,会明显有闪烁等情况。
第二种方式很复杂,但是效率和复用性高,开放各种扩张属性之后,可以适用于大部分场景。
以前用了很多次第一种方案,每次新做APP,都得重新设计界面,很不便利。这次,我准备采用第二种方案来做一个公用的皮肤。
关于GDI+,我只能算一个新人,不做具体的介绍,这里只讲我的一些实现方式,计划项目完成后,开源到github。
绘制标题栏
做自定义界面,绕不开一个问题就是绘制标题栏。
每个Winform窗体,可以分为两个部分:非客户区域和客户区域。
非客户区域:表示无法由我们程序猿绘制的部分,具体包括:窗口标题栏,边框
客户区域:表示由我们程序猿绘制的部分,也就是窗体内容,平时我们拖控件都是拖到客户区域
一般自定义窗口的实现方式无非以下种
1.设置窗口为无边框窗口,顶部放一个Panel,设置Panel.Dock=Top,然后在Panel里面绘制logo、标题、按钮等元素。
2.拦截窗口消息,重写WndProc方法,拦截窗口标题绘制消息,由自己手工绘制
很多人会为了简便,采用第一种方式,不过缺点比较明显,对于我来说,最主要的一点就是真正的实现界面,里面的控件元素Dock会受到影响,不利于客户区域布局。
高手牛人会采用第二种方式,不是我这种Winform小白的菜,所以,我采用第三种方式,也是本篇文章的核心思想。
采用无边框窗口,设置窗口Padding.Top为标题栏高度,采用GDI+绘制标题栏元素。
这种方式的好处显而易见
具体实现窗体子控件Dock不受影响
无边框之后,重写窗体拖动事件不需要对标题栏每一个元素进行事件处理
标题栏高度可随时自定义
本文开头的几个截图,标题栏绘制代码如下
绘制标题文字、Logo图片
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
|
绘制最小化、最大化、关闭、帮助按钮
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
|
窗体OnPaint事件,自绘标题栏
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
采用Padding来约束子实现界面的元素布局位置
当我采用了无边框窗体来做自定义皮肤之后,由于去除了非客户区域(标题栏、边框),子实现窗体的坐标位置(0,0)实际上应该会覆盖我的标题栏,不过,反编译.NET源码之后,我发现Form类有一个Padding属性,这个属性继承自Control类,它的作用与CSS中的padding相同。所以,我决定使用这个技术来约束子实现界面的元素布局位置。
每次修改标题栏高度时,需要重新生成窗体的Padding属性
1 2 3 |
|
每次修改边框宽度时,需要重新生成窗体的Padding属性
1 2 3 |
|
最后,隐藏掉Padding属性,外部修改无效
1 |
|
附加1:标题栏自绘按钮悬浮背景色修改和单击事件处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
|
protected override void OnMouseClick(MouseEventArgs e)
{
var point = new Point(e.X, e.Y);
if (this.closeRect != Rectangle.Empty && this.closeRect.Contains(point))
{
this.Close();
return;
}
if (!this.maxRect.IsEmpty && this.maxRect.Contains(point))
{
if (this.WindowState == FormWindowState.Maximized)
{
this.WindowState = FormWindowState.Normal;
}
else
{
this.WindowState = FormWindowState.Maximized;
}
this.maxHover = false;
return;
}
if (!this.minRect.IsEmpty && this.minRect.Contains(point))
{
this.WindowState = FormWindowState.Minimized;
this.minHover = false;
return;
}
if (!this.helpRect.IsEmpty && this.helpRect.Contains(point))
{
this.helpHover = false;
this.Invalidate(this.captionRect);
CancelEventArgs ce = new CancelEventArgs();
base.OnHelpButtonClicked(ce);
return;
}
base.OnMouseClick(e);
}
1 |
|
附加2:处理无边框窗体用户调整大小
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
|
全类文件,不晓得咋上传附件,所以没传,要的可以找我QQ。
2016年6月22日编辑添加:
由于本人在北京出差,昨晚上飞机航班延误,根本没想到突然这么多人要源码,无法做到一一回应,请大家谅解,我已经将DForm类上传,感谢“大萝卜控”给我提示。
请大家点击 这里 下载。
里面有几张图片,大家可以随便弄下,我出差比较忙,回去之后,再放github,到时再开个单章通知大家。
关于阴影的部分,大家可以先注释掉代码,完整源码放出之后,就可以了。
还有哟,我QQ在文章某个地方有显示,没加码。
很多人要源码,以前做的找不到了,新发一个,用的东西差不多。拿去吧。
https://github.com/dongger/MomoForm
懒惰,是一个通病。 努力,必会成为一种习惯。
[DForm]我也来做自定义Winform之另类标题栏重绘相关推荐
- DataTable列自定义渲染切页无效重绘
DataTable列自定义渲染切页 进行DataTable重绘 jsp代码 table = $("#detail_table").DataTable({language: lang ...
- WinForm经典窗体皮肤[重绘]
先上图看看效果: 1.默认经典 2.蓝色炫雅 3.蓝色经典 4.黑色炫雅 5.黑色经典 注:代码是几年前从网上找到的,好像是在CodeProject上,代码整理中,稍候公开源码... 转载于:http ...
- .Net(C#)自定义WinForm控件之小结篇(强力推荐)
强力推荐的网站:http://www.myfirm.cn/News/dotNetGUIAPI/ 本文转载:http://www.myfirm.cn/News/dotNetUserInterface/2 ...
- 背水一战 Windows 10 (20) - 绑定: DataContextChanged, UpdateSourceTrigger, 对绑定的数据做自定义转换...
背水一战 Windows 10 (20) - 绑定: DataContextChanged, UpdateSourceTrigger, 对绑定的数据做自定义转换 原文:背水一战 Windows 10 ...
- 重绘Winform窗体
本文转载自:http://www.cnblogs.com/encoding/p/5603080.html 按照惯例,先来几张样例图(注:为了展示窗口阴影效果,截图范围向外扩展了些,各位凭想象吧). 还 ...
- winform控件大小改变是防止背景重绘导致的闪烁
在工作中需要做一个伸缩控件,这个自定义控件继承于Panel.这个伸缩控件分为两个部分,头部是一个自定义组件,伸缩控件的背景为灰色,头部背景要求白色.伸缩控件在点击按钮时会重绘,同时他内部的控件也会重绘 ...
- winform 异步弹窗窗体_玩转控件:重写/重绘Dev中MessageBox弹窗控件
很久没有更新博客了,本想着直接发一篇<手撕ERP>系列,从控件重写.重绘,到框架搭建,再到部分模块实现+业务的.但是每次动手的时候,都觉得难以下手.直接从数据库设计开始吧,模块设计还没定下 ...
- 自定义字体样式引入使用方法、文本阴影、边框阴影、(边框)圆角、渐变、理解重绘与回流、渐进增强和优雅降级的区别
目录 1.文本阴影 text-shadow 2.边框阴影 box-shadow 3.自定义字体样式方法 引入与使用方法举例: 4.(边框)圆角 5.渐变 6.过渡 transition 7.理论知识 ...
- c#-winform重绘Tabcontrol控件,标签带Logo图标
模仿网页浏览器标签重绘Tabcontrol控件,每个标签页左上角的Logo图标可以自定义,当然图标也可以挪到右边,直接上图.
最新文章
- java邮件接收代码,JavaMail入门第四篇 接收邮件(示例代码)
- springcloud与dubbo对比:
- 自然语言处理ACL2020论文列表
- Android6.0------权限申请管理(单个权限和多个权限申请)
- Uipath 学习栏目基础教学:6Uipath发送邮件
- python中格式化字符串_Python中所有字符串格式化的指南
- 用于 Keras 用户使用的 TensorFlow.js layers API
- ibatis调用mysql函数
- Sql Server 全文检索
- Mybatis mapper.xml中常用标签详解
- 正三角形二面体群表示为二阶矩阵形式
- 解决屏幕大小不一导致页面下方出现多余空白的问题
- android plc,基于Android的智能PLC操控软件设计与实现
- Android 开发、测试工具资源汇总
- 最新Android 9.0 Pie,你想知道的都在这了
- odoo10 -- 请假模块
- 听声音做钥匙?!慢放开锁音轨,黑客就能破解常用门锁
- 华为服务器命令行修改密码,华为IAD命令行配置方法
- 荐9个可以帮助你的公众号
- 华为nova5 pro怎么升级鸿蒙系统,鸿蒙系统终于来了!这几款华为手机都可以升级了...