[WPF自定义控件库]使用WindowChrome自定义RibbonWindow
1. 为什么要自定义RibbonWindow
自定义Window有可能是设计或功能上的要求,可以是非必要的,而自定义RibbonWindow则不一样:
- 如果程序使用了自定义样式的Window,为了统一外观需要把RibbonWindow一起修改样式。
- 为了解决RibbonWindow的BUG。
如上图所示,在Windows 10 上运行打开RibbonWindow,可以看到标题栏的内容(包括分隔符)没有居中对齐,缺少下边框。
在最大化的时候标题栏内容甚至超出屏幕范围。
WPF提供的Ribbon是个很古老很古老的控件,附带的RibbonWindow也十分古老。RibbonWindow在以前应该可以运行良好,但多年没有更新,在.NET 4.5(或者说是WIN7平台,我没仔细考究)后就出现了这个问题。作为专业软件这可能没法接受,而这个问题微软好像也没打算修复。以前的做法通常是使用Fluent.Ribbon之类的第三方组件,因为我已经在Kino.Toolkit.Wpf中提供了使用WindowChrome自定义的Window,为了统一外观于是顺手自定义一个ExtendedRibbonWindow。
2. 问题产生的原因
RibbonWindow是派生自Window,并使用了WindowChrome,它的ControlTemplate大概是这样:
<Grid><Border Name="PART_ClientAreaBorder"Background="{TemplateBinding Control.Background}"BorderBrush="{TemplateBinding Control.BorderBrush}"BorderThickness="{TemplateBinding Control.BorderThickness}"Margin="{Binding Path=(SystemParameters.WindowNonClientFrameThickness)}" /><Border BorderThickness="{Binding Path=(WindowChrome.WindowChrome).ResizeBorderThickness, RelativeSource={RelativeSource TemplatedParent}}"><Grid><Image Name="PART_Icon"WindowChrome.IsHitTestVisibleInChrome="True"HorizontalAlignment="Left"VerticalAlignment="Top"Width="{Binding Path=(SystemParameters.SmallIconWidth)}"Height="{Binding Path=(SystemParameters.SmallIconHeight)}" /><AdornerDecorator><ContentPresenter Name="PART_RootContentPresenter" /></AdornerDecorator><ResizeGrip Name="WindowResizeGrip"WindowChrome.ResizeGripDirection="BottomRight"HorizontalAlignment="Right"VerticalAlignment="Bottom"Visibility="Collapsed"IsTabStop="False" /></Grid></Border>
</Grid>
Ribbon的Chrome部分完全依赖于WindowChrome,PART_ClientAreaBorder负责为ClientArea提供背景颜色。在PART_ClientAreaBorder后面的另一个Border才是真正的ClientArea部分,它用于放置Ribbon。因为Ribbon的一些按钮位于标题栏,所以Ribbon必须占用标题栏的位置,并且由Ribbon显示原本应该由Window显示的标题。WindowChrome的标题栏高度是SystemParameters.WindowNonClientFrameThickness.Top,在Windows 10,100% DPI的情况下为27像素。而Ribbon标题栏部分使用了SystemParameters.WindowCaptionHeight作为高度,这个属性的值为23,所以才会出现对不齐的问题。
<DockPanel Grid.Column="0" Grid.ColumnSpan="3" LastChildFill="True" Height="{Binding Path=(SystemParameters.WindowCaptionHeight)}">
而最大化的时候完全没有调整Ribbon的Margin,并且WindowChrome本身在最大化就会有问题。所以不能直接使用WindowChrome,而应该使用自定义的UI覆盖WindowChrome的内容。
3. 自定义RibbonWindow
我在Kino.Toolkit.Wpf提供了一个自定义RibbonWindow,基本上代码和ControlTempalte与自定义Window一样,运行效果如上图所示。在自定义RibbonWindow里我添加了RibbonStyle属性,默认值是一个解决Ribbon标题栏问题的Ribbon样式,里面使用SystemParameters.WindowNonClientFrameThickness作为标题的高度。
<DockPanel Grid.Column="0"Grid.ColumnSpan="3"Margin="0,-1,0,0"Height="{Binding Path=(SystemParameters.WindowNonClientFrameThickness).Top}"LastChildFill="True">
RibbonWindow还添加了一个StyleTypedProperty:
[StyleTypedProperty(Property = nameof(RibbonStyle), StyleTargetType = typeof(Ribbon))]
StyleTypedProperty 应用于类定义并确定类型为 TargetType 的属性的 Style。使用了这个属性的控件可以在Blend中使用 "右键"->"编辑其他模板"->"编辑RibbonSytle" 创建Ribbon的Style。
不过虽然我这么贴心地加上这个Attribute,但我的Blend复制Ribbon模板总是报错。
4. 结语
我也见过一些很专业的软件没处理RibbonWindow,反正外观上的问题忍一忍就过去了,实在受不了可以买一个有现代化风格的控件库,只是为了标题栏对不齐这种小事比较难说服上面同意引入一个新的组件。除了使用我提供的解决方案,stackoverflow也由不少关于这个问题的讨论及解决方案可供参考,例如这个:
c# - WPF RibbonWindow + Ribbon = Title outside screen - Stack Overflow
顺便一提,ExtendedRibbonWindow需要继承RibbonWindow,所以没法直接集成ExtendedWindow。因为ExtendedWindow很多功能都试用附加属性和控件代码分离,所以ExtendedRibbonWindow需要重复的代码不会太多。
5. 参考
RibbonWindow Class (System.Windows.Controls.Ribbon) Microsoft Docs
Ribbon Class (System.Windows.Controls.Ribbon) Microsoft Docs
WindowChrome Class (System.Windows.Shell) Microsoft Docs
SystemParameters Class (System.Windows) Microsoft Docs
StyleTypedPropertyAttribute Class (System.Windows) Microsoft Docs
6. 源码
Kino.Toolkit.Wpf_Window at master
转载于:https://www.cnblogs.com/lonelyxmas/p/11015950.html
[WPF自定义控件库]使用WindowChrome自定义RibbonWindow相关推荐
- [WPF自定义控件库]自定义Expander
[WPF自定义控件库]自定义Expander 原文:[WPF自定义控件库]自定义Expander 1. 前言 上一篇文章介绍了使用Resizer实现Expander简单的动画效果,运行效果也还好,不过 ...
- [WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互
[WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互 原文:[WPF自定义控件库] 自定义控件的代码如何与ControlTemplate交互 1. 前言 WPF有一个灵活的 ...
- 【转】WPF自定义控件与样式(13)-自定义窗体Window 自适应内容大小消息框MessageBox...
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等. 本文主要内容: 自定义Window窗体样式: 基于自定义窗体实现自定义MessageB ...
- WPF自定义控件与样式(13)-自定义窗体Window 自适应内容大小消息框MessageBox
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 自定义 ...
- [WPF自定义控件库]以Button为例谈谈如何模仿Aero2主题
1. 为什么选择Aero2 除了以外观为卖点的控件库,WPF的控件库都默认使用"素颜"的外观,然后再提供一些主题包.这样做的最大好处是可以和原生控件或其它控件库兼容,而且对于大部分 ...
- [WPF自定义控件] 开始一个自定义控件库项目
1. 目标 我实现了一个自定义控件库,并且打算用这个控件库作例子写一些博客.这个控件库主要目标是用于教学,希望通过这些博客初学者可以学会为自己或公司创建自定义控件,并且对WPF有更深入的了解. 控件库 ...
- WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox
一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接. 本文主要内容: 下拉选 ...
- WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展
原文:WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展 一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐 ...
- WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式
原文:WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式 一.前言 申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等, ...
最新文章
- linux查看wan的ip地址,查看wan口ip地址操作方法
- 深度学习caffe的代码怎么读?
- 大数据产业不只是建设数据中心
- 编译时和运行时、OC中对象的动态编译机制
- 改变bantchsize发现loss增大_肺内发现磨玻璃结节,一定就是早期肺癌吗?
- 【Qt】QLayoutItem类
- Kubernetes 1.5部署sonarqube
- sim800 模式切换_SIM的完整形式是什么?
- 可逆矩阵的秩等于矩阵的阶数_矩阵论一些总结点
- Docker,使生信分析更简单、可重复
- 表单html遇到的问题及处理,Web前端开发中常见问题及解决方案
- OPENCV数据结构体系和常用函数
- shell ftp上传下载文件
- 计算机专业立项课题研究,计算机类课题研究选题参考
- CSAPP 存储器山数据的测量以及绘制,Cache lab part A:Cache simulator
- 关于微信小程序 Error: errCode: -501001 resource system error | errMsg: Environment not found; 错误解决方案
- CentOS7转发非3306端口到3306端口
- TextView添加下划线
- 我的世界服务器物品在护甲,我的世界满级护甲指令,我的世界召唤盔甲架指令...
- 9月6日关键点检测学习笔记——人脸和手部特征点检测
热门文章
- 湖北生物科技职业学院计算机专业分数线,湖北生物科技职业学院录取分数线2021是多少分(附历年录取分数线)...
- mysql数据库事件不执行_【数据库】mysql查看事件是否执行
- html鼠标拖尾效果,JS实现鼠标移动拖尾
- 保密检查便携式计算机,Lyaept关于便携式计算机和移动存储介质保密管理制度.doc...
- mysql5.7zib配置_mysql-5.7.13 解压版安装教程
- mysql单表约束为_MySQL 表约束
- 安卓android中国象棋chess程序项目源码源代码,C/C++编程笔记:C语言打造中国象棋游戏,项目源代码分享!,c语言笔记大全...
- python | 关键词快速匹配检索小工具 pyahocorasick / ahocorapy
- 笔记+R︱信用风险建模中神经网络激活函数与感知器简述
- 语义模型及自然语言处理系统基础算法