wpf 如何7步写一个badge控件
首先看一下效果:

任意控件可以附加一个文字在控件的右上角,并带有红色背景
第一步,新建一个空的wpf项目:
第二步,创建一个类,取名为badge:
第三步,将badge的父类设置成 System.Windows.Documents.Adorner
public class Badge : Adorner
{
public Badge(UIElement adornedElement) : base(adornedElement)
{ }
}
里面的adornedElement表示badge后面附加的对象
关于Adorner这个类的说明,微软给了相应的教程 https://learn.microsoft.com/zh-cn/dotnet/desktop/wpf/controls/adorners-overview?view=netframeworkdesktop-4.8
也可以F11查看Adorner类的说明.
第4步,给badge添加一个Content的附加属性:
public static readonly DependencyProperty ContentProperty;
static Badge()
{
ContentProperty = DependencyProperty.RegisterAttached("Content", typeof(string), typeof(Badge),
new FrameworkPropertyMetadata(string.Empty, new PropertyChangedCallback(ContentChangedCallBack)));
}
public static string GetContent(DependencyObject obj)
{
return (string)obj.GetValue(ContentProperty);
}
public static void SetContent(DependencyObject obj, string value)
{
obj.SetValue(ContentProperty, value);
}
第5步,实现content的回调方法:
private static void ContentChangedCallBack(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var target = d as FrameworkElement;
if (target != null)
{
if (target.IsLoaded)
{
var layer = AdornerLayer.GetAdornerLayer(target);
if (layer != null)
{
var Adorners = layer.GetAdorners(target);
if (Adorners != null)
{
foreach (var adorner in Adorners)
{
if (adorner is Badge)
{
layer.Remove(adorner);
}
}
}
layer.Add(new Badge(target));
}
}
else
{
target.Loaded += (sender, ae) =>
{
var layer = AdornerLayer.GetAdornerLayer(target);
if (layer != null)
{
var Adorners = layer.GetAdorners(target);
if (Adorners != null)
{
foreach (var adorner in Adorners)
{
if (adorner is Badge)
{
layer.Remove(adorner);
}
}
}
layer.Add(new Badge(target));
}
};
}
}
}
第6步,重写一下OnRender方法:
protected override void OnRender(DrawingContext drawingContext)
{
var element = this.AdornedElement as FrameworkElement;
Rect adornedElementRect = new Rect(element.DesiredSize);
var point = adornedElementRect.TopRight;
point.X = adornedElementRect.Right - element.Margin.Left - element.Margin.Right; SolidColorBrush renderBrush = new SolidColorBrush(Colors.Red);
Pen renderPen = new Pen(new SolidColorBrush(Colors.Red), 0.5);
double renderRadius = 5; var content = this.AdornedElement.GetValue(Badge.ContentProperty).ToString();
FormattedText formattedText = new FormattedText(content, CultureInfo.GetCultureInfo("zh-cn"), FlowDirection.LeftToRight, new Typeface("Verdana"), 10, Brushes.White);
var textWidth = formattedText.Width;
var textHeight = formattedText.Height;
var rectangleSizeWidth = textWidth < 15 ? 15 : textWidth;
var rectangleSizeHeight = textHeight < 15 ? 15 : textHeight;
var size = new Size(rectangleSizeWidth, rectangleSizeHeight);
Rect rect = new Rect(new Point(point.X - rectangleSizeWidth / 2, point.Y - rectangleSizeHeight / 2), size); drawingContext.DrawRoundedRectangle(renderBrush, renderPen, rect, renderRadius, renderRadius);
drawingContext.DrawText(formattedText, new Point(point.X - textWidth / 2, point.Y - textHeight / 2));
}
这段代码就是在目标控件的右上角绘制一个带圆角的rectangle,背景色为红色,再绘制一个文本用来显示content.
第7步,运用到项目中:
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<cc:CornerButton ButtonType="OutLine" Width="200" Height="30"
cc:Badge.Content="{Binding ElementName=textbox1, Path=Text, UpdateSourceTrigger=PropertyChanged}" Margin="10"/>
<cc:CornerTextBox x:Name="textbox1" Width="200" Height="30" Text="12"
VerticalContentAlignment="Center" WaterText="BadgeContent"/>
</StackPanel>
cc是表示badge所在的命名空间,然后你就会发现,你改变textbox的值的时候,badge会跟着textbox的值发生变化哦.
项目github地址:bearhanQ/WPFFramework: Share some experience (github.com)
QQ技术交流群:332035933;
wpf 如何7步写一个badge控件的更多相关文章
- WPF自定义控件(二)の重写原生控件样式模板
话外篇: 要写一个圆形控件,用Clip,重写模板,去除样式引用圆形图片可以有这三种方式. 开发过程中,我们有时候用WPF原生的控件就能实现自己的需求,但是样式.风格并不能满足我们的需求,那么我们该怎么 ...
- appium+python:自己写的一个滑动控件的方式
#调用方式roll_ele("ID","ele_id","7","up",3)#将控件分为7格,从底部倒数第二格向上滑动 ...
- 一步一步写一个简单通用的makefile(三)
上一篇一步一步写一个简单通用的makefile(二) 里面的makefile 实现对通用的代码进行编译,这一章我将会对上一次的makefile 进行进一步的优化. 优化后的makefile: #Hel ...
- WPF基础知识、界面布局及控件Binding(转)
WPF是和WinForm对应的,而其核心是数据驱动事件,在开发中显示的是UI界面和逻辑关系相分离的一种开放语言.UI界面是在XAML语言环境下开发人员可以进行一些自主设计的前台界面,逻辑关系还是基于c ...
- WPF基础知识、界面布局及控件Binding
WPF是和WinForm对应的,而其核心是数据驱动事件,在开发中显示的是UI界面和逻辑关系相分离的一种开放语言.UI界面是在XAML语言环境下开发人员可以进行一些自主设计的前台界面,逻辑关系还是基于c ...
- WPF 构建无外观(Lookless)控件
原文:WPF 构建无外观(Lookless)控件 构建一个用户可以使用Template属性设置外观的WPF控件需要以下几步 1.继承自System.Windows.Controls.Control 2 ...
- 《Programming WPF》翻译 第5章 7.控件模板
原文:<Programming WPF>翻译 第5章 7.控件模板 如果仔细的看我们当前的TTT游戏,会发现Button对象并没有完全为我们工作.哪些TTT面板有内圆角? 图5-14 这里 ...
- WPF从我炫系列4---装饰控件的用法
这一节的讲解中,我将为大家介绍WPF装饰控件的用法,主要为大家讲解一下几个控件的用法. ScrollViewer滚动条控件 Border边框控件 ViewBox自由缩放控件 1. ScrollView ...
- WPF教程002 - 实现Step步骤条控件
原文:WPF教程002 - 实现Step步骤条控件 在网上看到这么一个效果,刚好在用WPF做控件,就想着用WPF来实现一下 1.实现原理 1.1.该控件分为2个模块,类似ComboBox控件分为Ste ...
- WPF中自定义的DataTemplate中的控件,在Window_Loaded事件中加载机制初探
原文:WPF中自定义的DataTemplate中的控件,在Window_Loaded事件中加载机制初探 最近因为项目需要,开始学习如何使用WPF开发桌面程序.使用WPF一段时间之后,感 ...
随机推荐
- Wireshark抓包分析理解DHCP协议及工作流程
一.DHCP简介 DHCP(Dynamic Host Configuration Protocol)动态主机配置协议,前身是BOOTP协议.在大型局域网中,需要给很多主机配置地址信息,如果采用传统 ...
- python重拾基础第四天
本节内容 迭代器&生成器 装饰器 Json & pickle 数据序列化 软件目录结构规范 作业:ATM项目开发 1. 列表生成式,迭代器&生成器 列表生成式 我现在有个需求, ...
- P2045 方格取数加强版题解
题目链接:P2045 方格取数加强版 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 题目: 出一个 n*n 的矩阵,每一格有一个非负整数 A{i,j}且A{i,j} <=10 ...
- SQL注入攻击及防御
SQL注入攻击及防御 1.项目实验环境 目标靶机OWASP_Broken_Web_App_VM_1.2: https://sourceforge.net/projects/owaspbwa/files ...
- mapreduce的shuffle机制
1.1 概述: mapreduce中,map阶段处理的数据如何传递给reduce阶段,是mapreduce框架中最关键的一个流程,这个流程就叫shuffle:(从map的输出到reduce的输入) s ...
- 随机数据下 Sqrt Tree 的平替实现
原理 在随机数据下,把原序列分成 \(\sqrt n\) 个块,维护每个块的前缀后缀最大值,那么,在随机询问下,对于在一个块中的询问,暴力查询. 复杂度 概率 $ n ^ {-\frac{1}{2}} ...
- ComfyUI基础篇:为什么要学 ComfyUI?
前言: 在AI生成图像领域,有许多产品,例如 Midjourney 和 Stability AI 等.为什么要学习 ComfyUI 呢?我斗胆带大家一起分析一下. 目录 1.Midjourney VS ...
- 使用Terminal.Gui构建功能强大的.NET控制台应用
前言 前段时间分享了一个库帮你轻松的创建漂亮的.NET控制台应用程序 - Spectre.Console的文章教程,然后就有小伙伴提问:.NET控制台应用需要应对强交互性的场景,有什么好的解决方案?, ...
- MySQL 索引失效
全列匹配 最佳左前缀法则 不在索引列上做任何操作(计算.函数.自动.手动类型转换),会导致索引失效 存储引擎不能使用索引中范围条件右边的列 尽量使用覆盖索引(只访问索引的查询(索引和查询列一致)),少 ...
- Java开发工具和历史版本
eclipse 的历史版本: 版本代号 平台版本 主要版本发行日期 SR1发行日期 SR2发行日期 SR3发行日期 代号名称 N/A 3.0 2004年6月21日 [2] N/A N/A N/A N ...