WPF 已知问题 Separator 无法应用 ContextMenu 定义的默认样式
本文记录一个 WPF 已知问题,在 ContextMenu 的 Resources 里定义 Separator 的默认样式,在 ContextMenu 里面的 Separator 将应用不上,或者说不会找到此默认的样式。需要明确给 Style 一个 Key 且在 Separator 写明此 Key 才能应用上
如下面的例子,在 ContextMenu 的 Resources 资源里面定义了 Separator 的默认样式
<ContextMenu>
<ContextMenu.Resources>
<Style TargetType="Separator">
<Setter Property="Margin" Value="10,10,10,10"></Setter>
</Style>
</ContextMenu.Resources>
</ContextMenu>
接着在 ContextMenu 里面存放一个 Separator 元素,可以看到此 Separator 元素没有使用或者说找到定义的样式,视觉上就是 Margin 没有生效
<ContextMenu>
<ContextMenu.Resources>
<Style TargetType="Separator">
<Setter Property="Margin" Value="10,10,10,10"></Setter>
</Style>
</ContextMenu.Resources>
<Separator></Separator>
</ContextMenu>
而如果给 Separator 的 Style 加上 Key 且在 Separator 写明了此 Key 那么将可以成功应用上,如下面代码
<ContextMenu>
<ContextMenu.Resources>
<Style x:Key="SeparatorStyle" TargetType="Separator">
<Setter Property="Margin" Value="10,10,10,10"></Setter>
</Style>
</ContextMenu.Resources>
<Separator Style="{StaticResource SeparatorStyle}"></Separator>
</ContextMenu>
此问题是在 WPF 代码里面写了特殊判断逻辑,预计是有我没有理解的坑才如此做。感谢 少珺 工具人帮我找到了在 WPF 框架里面的问题
为了方便说明问题,我将给出可以运行的测试代码,此测试代码可以在本文末尾找到项目的下载
新建一个 WPF 项目,编辑主窗口,添加以下代码
<Grid Background="White" MouseDown="Grid_OnMouseDown">
<Grid.ContextMenu>
<ContextMenu>
<ContextMenu.Resources>
<Style TargetType="Separator">
<Setter Property="Margin" Value="10,10,10,10"></Setter>
</Style>
<Style x:Key="SeparatorStyle" TargetType="Separator">
<Setter Property="Margin" Value="10,10,10,10"></Setter>
</Style>
</ContextMenu.Resources>
<Menu>1</Menu>
<Menu>2</Menu>
<Menu>3</Menu>
<Separator></Separator>
<Menu>1</Menu>
<Menu>2</Menu>
<Menu>3</Menu>
<Separator Style="{StaticResource SeparatorStyle}"></Separator>
<Menu>1</Menu>
<Menu>2</Menu>
<Menu>3</Menu>
</ContextMenu>
</Grid.ContextMenu>
</Grid>
对应的后台代码如下
private void Grid_OnMouseDown(object sender, MouseButtonEventArgs e)
{
var grid = (Grid)sender;
grid.ContextMenu.IsOpen = true;
}
此时点击窗口内容,即可看到弹出了菜单
弹出的菜单的两条分割线的 Margin 是不相同的
根本原因是在 WPF 里面,对于在 Menu 里面的 Separator 采用的是如下逻辑,以下代码可以从 WPF 官方开源仓库 https://github.com/dotnet/wpf/blob/1aab9e3f42dbf550797bff97a32f2dbfb61a3198/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/MenuItem.cs#L1344-L1353 找到。我此问题报告给 WPF 官方,请看 https://github.com/dotnet/wpf/issues/7268
Separator separator = item as Separator;
if (separator != null)
{
bool hasModifiers;
BaseValueSourceInternal vs = separator.GetValueSource(StyleProperty, null, out hasModifiers);
if (vs <= BaseValueSourceInternal.ImplicitReference)
separator.SetResourceReference(StyleProperty, SeparatorStyleKey);
separator.DefaultStyleKey = SeparatorStyleKey;
}
从上面代码可以看到,判断如果样式是小于等于 ImplicitReference 优先级的,那就采用默认的 SeparatorStyleKey 作为样式属性。如果没有在代码里面明确给定资源的 Key 内容,那以上代码的 vs 就是 ImplicitReference 优先级,于是样式就被修改为默认的主题样式
这是在 WPF 里面特别给定的代码,也许是大佬们为了修复某个我理解不了的坑
可以通过如下方式获取本文的源代码,先创建一个空文件夹,接着使用命令行 cd 命令进入此空文件夹,在命令行里面输入以下代码,即可获取到本文的代码
git init
git remote add origin https://gitee.com/lindexi/lindexi_gd.git
git pull origin b820847a1af20370de28a1e73e32df9561a98ecc
以上使用的是 gitee 的源,如果 gitee 不能访问,请替换为 github 的源。请在命令行继续输入以下代码
git remote remove origin
git remote add origin https://github.com/lindexi/lindexi_gd.git
git pull origin b820847a1af20370de28a1e73e32df9561a98ecc
获取代码之后,进入 HayhachujedaKikunayreefee 文件夹
更多 WPF 已知问题请参阅 博客导航
大佬 czdietrich 告诉我说,这是特意的。原因是 Separator 在很多个地方都会使用,如果在 Menu 里,也采用默认继承的关系,将会让 Separator 的样式打架。毕竟在 Menu 里面的,是期望比较特殊一些的。于是就限制了,如果是放在 Menu 里面,应该采用的是 MenuItem.SeparatorStyleKey 样式的才会作为默认的继承样式,如下面代码
<Window x:Class="TestContextMenuSeparatorStyle.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Window.Resources>
<Style x:Key="{x:Static MenuItem.SeparatorStyleKey}" TargetType="Separator">
<Setter Property="Background" Value="Tomato" />
</Style>
</Window.Resources>
<Grid Background="White">
<Grid.ContextMenu>
<ContextMenu>
<MenuItem Header="Item 1" />
<Separator />
<MenuItem Header="Item 2" />
</ContextMenu>
</Grid.ContextMenu>
</Grid>
</Window>
以上的代码也符合 WPF 的逻辑,详细请看 https://github.com/dotnet/wpf/issues/7268#issuecomment-1315303718
WPF 已知问题 Separator 无法应用 ContextMenu 定义的默认样式的更多相关文章
- WPF 左键单击弹出菜单 ContextMenu
原文:WPF 左键单击弹出菜单 ContextMenu WPF中的ContextMenu在XAML中可直接做出来,但是仅限于右键弹出菜单,如果需要添加左键弹出功能,只需要在事件中添加Click事件 X ...
- 风口之下,猪都能飞。当今中国股市牛市,真可谓“错过等七年”。 给你一个回顾历史的机会,已知一支股票连续n天的价格走势,以长度为n的整数数组表示,
转自:http://www.cnblogs.com/ranranblog/p/5845010.html 风口之下,猪都能飞.当今中国股市牛市,真可谓“错过等七年”. 给你一个回顾历史的机会,已知一支股 ...
- Delphi 查找标题已知的窗口句柄,遍历窗口控件句柄(转)
用我的方法来控制其他程序窗体上的窗口控件,必须先了解什么是 回调函数.我的理解是这样的: 回 调函数写出来不是自己的程序去调用的,反而是让其他的东西去调用,比如windows操作系统,比如其他的程序等 ...
- 对象布局已知时 C++ 对象指针的转换时地址调整
在我调试和研究 netscape 系浏览器插件开发时,注意到了这个问题.即,在对象布局已知(即对象之间具有继承关系)时,不同类型对象的指针进行转换(不管是隐式的从下向上转换,还是强制的从上到下转换)时 ...
- ARCgis已知线裁剪已知面
经常遇到需要在ArcGIS中,根据已知线图层(要素)切分已知面图层(要素).经过研究,利用topology拓扑菜单中的construct features可以实现.具体如下 现有用线图层A.面图层B, ...
- Java集合-5. (List)已知有一个Worker 类如下: 完成下面的要求 1) 创建一个List,在List 中增加三个工人,基本信息如下: 姓名 年龄 工资 zhang3 18 3000 li4 25 3500 wang5 22 3200 2) 在li4 之前插入一个工人,信息为:姓名:zhao6,年龄:24,工资3300 3) 删除wang5 的信息 4) 利用for 循
第六题 5. (List)已知有一个Worker 类如下: public class Worker { private int age; private String name; private do ...
- JAVA-集合作业-已知有十六支男子足球队参加2008 北京奥运会。写一个程序,把这16 支球队随机分为4 个组。采用List集合和随机数
第二题 已知有十六支男子足球队参加2008 北京奥运会.写一个程序,把这16 支球队随机分为4 个组.采用List集合和随机数 2008 北京奥运会男足参赛国家: 科特迪瓦,阿根廷,澳大利亚,塞尔维亚 ...
- WCF 已知类型和泛型解析程序 KnownType
数据协定继承 已知类型和泛型解析程序 Juval Lowy 下载代码示例 自首次发布以来,Windows Communication Foundation (WCF) 开发人员便必须处理数据协定继承方 ...
- 【编程题目】n 支队伍比赛,分别编号为 0,1,2。。。。n-1,已知它们之间的实力对比关系,
36.引用自网友:longzuo(运算)谷歌笔试: 19n 支队伍比赛,分别编号为 0,1,2....n-1,已知它们之间的实力对比关系,存储在一个二维数组 w[n][n]中,w[i][j] 的值代表 ...
- 已知树的前序、中序,求后序的java实现&已知树的后序、中序,求前序的java实现
public class Order { int findPosInInOrder(String str,String in,int position){ char c = str.charAt(po ...
随机推荐
- tomcat正常启动,但网页拒绝连接的解决方法
当发生拒绝连接的时候 1.首先要排除端口的占用 上一篇文章已经详细介绍了,这里不再赘述tomcat端口配置 2.设置防火墙放行tomcat 3.配置环境变量 此电脑→属性→高级系统设置→环境变量 点击 ...
- App启动页面优化
目录介绍 01.存在白屏问题 1.1 问题描述 1.2 问题分析 02.解决白屏的办法 2.1 解决方案分析 2.2 第一种解决方案 2.3 第二种解决方案 2.4 注意要点 03.Applicati ...
- 探讨三维模型OBJ格式轻量化在三维展示效果上的重要性
探讨三维模型OBJ格式轻量化在三维展示效果上的重要性 三维模型的OBJ格式轻量化在三维展示效果方面具有重要性.以下是对三维模型OBJ格式轻量化在三维展示效果上的重要性进行分析: 1.提高渲染性能:原始 ...
- FFmpeg开发笔记(五)更新MSYS的密钥环
<FFmpeg开发实战:从零基础到短视频上线>一书提到:使用MSYS对FFmpeg进行交叉编译时,需要事先安装交叉编译工具链,也就是执行下面命令. pacman -S mingw-w6 ...
- JDK8 ::用法(双冒号)
JDK8中有双冒号的用法,就是把方法当做参数传到stream内部,使stream的每个元素都传入到该方法里面执行一下. List<String> lt = Arrays.asList(&q ...
- win10注册表各种配置
注册表教程 lesson combination of images step: 1_注册右键特定类型文件指令 step: 2_注册新建文件类型指令 step: 3_新建文件夹右键菜单 step: 4 ...
- verilog之readmemb
verilog之readmemb 1.基本作用 用于读取存储器的值的系统函数.这里首先要知道什么是存储器.在verilog中,有一些比较大的数据是需要存储的,一般需要使用存储器,语法结构类似二维数组. ...
- 温馨提示:不注意这几点,PDT(产品开发团队)就得散!
在IPD(集成产品开发)体系中,PDT(Product Development Team,产品开发团队)发挥着至关重要的作用.PDT是一个跨部门.跨职能的协作团队,其成员来自不同的专业领域,包括研发. ...
- 7 HTML锚点应用
7 锚点应用 锚点( anchor )是超链接的一种应用,也叫命名锚记,锚点可以像一个定位器一样,可以实现页面内的链接跳转,运用相当普遍.例如,我们有一个网页,由于内容太多,导致页面很长,而且里面的内 ...
- 深入解析 C 语言中的 for 循环、break 和 continue
C语言中的 for 循环 当您确切地知道要循环执行代码块的次数时,可以使用 for 循环而不是 while 循环 for (语句 1; 语句 2; 语句 3) { // 要执行的代码块 } 语句 ...