WPF 水印装饰器
使用AdornerDecorator装饰器实现WPF水印
水印装饰器WatermarkAdorner类代码:

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Documents;
using System.Windows.Media; namespace WPF水印装饰器
{
/// <summary>
/// 水印装饰器
/// </summary>
public class WatermarkAdorner : Adorner
{
private string _watermarkText; public WatermarkAdorner(UIElement adornedElement, string watermarkText) : base(adornedElement)
{
_watermarkText = watermarkText;
this.IsHitTestVisible = false; //使水印不捕获事件
} protected override void OnRender(DrawingContext drawingContext)
{
Rect rect = new Rect(this.AdornedElement.RenderSize);
double centerX = rect.Right / 2.0;
double centerY = rect.Bottom / 2.0; drawingContext.PushOpacity(0.5);
RotateTransform rotateTransform = new RotateTransform(45, centerX, centerY);
drawingContext.PushTransform(rotateTransform); RotateTransform rt = new RotateTransform(-45, centerX, centerY);
Point point = default(Point);
double n = 5.0;
double margin = 40;
double halfWidth = GetTextLength(_watermarkText) * 10 / 2.0; //第1排3个
point = RotatePoint(0.5, 0.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText);
point = RotatePoint(2.5, 0.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText);
point = RotatePoint(4.5, 0.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText); //第2排2个
point = RotatePoint(1.5, 1.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText);
point = RotatePoint(3.5, 1.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText); //第3排3个
point = RotatePoint(0.5, 2.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText);
point = RotatePoint(2.5, 2.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText);
point = RotatePoint(4.5, 2.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText); //第4排2个
point = RotatePoint(1.5, 3.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText);
point = RotatePoint(3.5, 3.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText); //第5排3个
point = RotatePoint(0.5, 4.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText);
point = RotatePoint(2.5, 4.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText);
point = RotatePoint(4.5, 4.5, n, rt, rect, margin);
DrawText(point.X, point.Y, halfWidth, drawingContext, _watermarkText); } private void DrawText(double x, double y, double textHalfWidth, DrawingContext drawingContext, string text)
{
int fontSize = 20;
SolidColorBrush colorBrush = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#eeeef2"));
Point point = new Point(x - textHalfWidth, y - fontSize / 2.0);
FormattedText formattedText = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("宋体"), fontSize, colorBrush);
drawingContext.DrawText(formattedText, point);
} /// <summary>
/// 旋转Point
/// </summary>
/// <param name="ratioX">文本中心点占区域宽度n等分的比例</param>
/// <param name="ratioY">文本中心点占区域长度n等分的比例</param>
/// <param name="n">区域长宽n等分</param>
/// <param name="rotateTransform">旋转对象</param>
/// <param name="rect">区域</param>
/// <param name="margin">Margin</param>
private Point RotatePoint(double ratioX, double ratioY, double n, RotateTransform rotateTransform, Rect rect, double margin)
{
return rotateTransform.Transform(new Point(ratioX / n * rect.Right, ratioY / n * (rect.Bottom - 2 * margin) + margin));
} #region 计算文本长度(汉字计为2 大写字母计为1.5 小写字母计为1)
/// <summary>
/// 计算文本长度(汉字计为2 大写字母计为1.5 小写字母计为1)
/// </summary>
private double GetTextLength(string text)
{
double length = 0; Regex reg1 = new Regex("[\u4E00-\u9FFF]|[\uFE30-\uFFA0]");
Regex reg2 = new Regex("[A-Z]"); foreach (char c in text)
{
if (reg1.IsMatch(c.ToString()))
{
length += 2;
}
else if (reg2.IsMatch(c.ToString()))
{
length += 1.5;
}
else
{
length += 1;
}
} return length;
}
#endregion }
}
如何使用:
在窗体或控件的Loaded方法中,添加如下代码:

UIElement uiElement = (UIElement)this.Content;
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(uiElement);
adornerLayer.Add(new WatermarkAdorner(uiElement, _watermarkText));
完整MainWindow.xaml代码:

<Window x:Class="WPF水印装饰器.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WPF水印装饰器"
mc:Ignorable="d"
Title="MainWindow" Height="1040" Width="1920" Loaded="Window_Loaded" WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation="CenterScreen" MouseRightButtonDown="Window_MouseRightButtonDown">
<Window.Template>
<ControlTemplate TargetType="{x:Type Window}">
<!-- ControlTemplate不包含AdornerDecorator,需要在ControlTemplate中添加AdornerDecorator -->
<AdornerDecorator>
<ContentPresenter />
</AdornerDecorator>
</ControlTemplate>
</Window.Template>
<Window.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="tmplBtn" TargetType="{x:Type Button}" >
<Border x:Name="border" Background="#068d6b" CornerRadius="5">
<TextBlock Text="{TemplateBinding Content}" Foreground="#ffffff" HorizontalAlignment="Center" VerticalAlignment="Center"></TextBlock>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="border" Property="Background" Value="#069d8b"></Setter>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</ResourceDictionary>
</Window.Resources>
<Grid x:Name="grid" Background="#094760">
<Button x:Name="button" Content="显示子窗体" Margin="0,0,0,0" Width="100" Height="35" Click="button_Click" Template="{StaticResource tmplBtn}"></Button>
<Button x:Name="button2" Content="显示子窗体2" Margin="0,100,0,0" Width="100" Height="35" Click="button2_Click" Template="{StaticResource tmplBtn}"></Button>
</Grid>
</Window>
注意:如果窗体或控件使用了ControlTemplate,因为ControlTemplate不包含AdornerDecorator,所以需要在ControlTemplate中添加AdornerDecorator。
完整MainWindow.xaml.cs代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes; namespace WPF水印装饰器
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
private string _watermarkText = "持续研发测试账号 34.8.99.64"; public MainWindow()
{
InitializeComponent();
} private void Window_Loaded(object sender, RoutedEventArgs e)
{
UIElement uiElement = (UIElement)this.Content;
AdornerLayer adornerLayer = AdornerLayer.GetAdornerLayer(uiElement);
adornerLayer.Add(new WatermarkAdorner(uiElement, _watermarkText));
} private void Window_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
this.Close();
} private void button_Click(object sender, RoutedEventArgs e)
{
Window2 win = new Window2(_watermarkText);
win.Owner = this;
win.WindowStartupLocation = WindowStartupLocation.CenterScreen;
win.Show();
} private void button2_Click(object sender, RoutedEventArgs e)
{
Watermark win = new Watermark(_watermarkText);
win.Owner = this;
win.WindowStartupLocation = WindowStartupLocation.CenterScreen;
win.Show();
}
}
}
缺陷:遮不住视频
效果图:

WPF 水印装饰器的更多相关文章
- WPF标注装饰器
标注 在许多地方我们都会用到标注,比如在画图中: 在Office中: 在Foxit Reader中: 在Blend中: 等等. 简介 以前,因项目上需要做标注,简单找了一下,没发现适合要求的控件(包括 ...
- WPF装饰器
装饰器定义: 装饰器是一种特殊类型的 FrameworkElement,用于向用户提供可视化提示. 对于其他用户,装饰器可用于将功能控点添加到元素中或提供有关控件的状态信息. 装饰器可以在不改变原有的 ...
- WPF和Expression Blend开发实例:Adorner(装饰器)应用实例
装饰器-- 表示用于修饰 UIElement 的 FrameworkElement 的抽象类 简单来说就是,在不改变一个UIElement结构的情况下,将一个Visual对象加到它上面. 应用举例: ...
- Adorner 装饰器
装饰器 Adorner 装饰器是WPF中较为常用的技术之一,也是不同于XAML的技术. 较为特殊. 特殊于装饰器全部由C#构成,不同于ControlTenmpate和Style的元素. 装饰器在某些方 ...
- Python高手之路【四】python函数装饰器
def outer(func): def inner(): print('hello') print('hello') print('hello') r = func() print('end') p ...
- python装饰器
今天看了装饰器的一些内容,感觉@修饰符还是挺抽象的. 装饰器就是在不用改变函数实现的情况下,附加的实现一些功能,比如打印日志信息等.需要主意的是装饰器本质是一个高阶函数,她可以返回一个函数. 装饰器需 ...
- Python(四)装饰器、迭代器&生成器、re正则表达式、字符串格式化
本章内容: 装饰器 迭代器 & 生成器 re 正则表达式 字符串格式化 装饰器 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等.装饰器是解 ...
- [原创]django+ldap实现单点登录(装饰器和缓存)
前言 参考本系列之前的文章,我们已经搭建了ldap并且可以通过django来操作ldap了,剩下的就是下游系统的接入了,现在的应用场景,我是分了2个层次,第一层次是统一认证,保证各个系统通过ldap来 ...
- PHP 装饰器模式
装饰器模式:是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能. [装饰器模式中主要角色] 抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这 ...
- python cookbook 学习系列(一) python中的装饰器
简介 装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.它经常用于有切面需求的场景,比如:插入日志.性能测试.事务处理.缓 ...
随机推荐
- java中Calendar日历类型常见方法
Calendar是Java中常用的时间处理工具之一,它提供了很多日历类型常见方法,下面是一些常用的方法及对应的代码和运行结果. 1. 如何创建 Calendar 日历对象 Calendar 是一个抽象 ...
- 吉客云与用友U8的系统数据集成对接方案
吉客云与用友U8之间的系统数据集成方案.吉客云作为一款电商ERP产品,旨在为企业的数字化升级提供全方位的支持.用友U8是一个经过多年发展的信息化管理系统,见证了企业信息化从简单到精细.从局部到全面的转 ...
- 洛谷3521 [POI2011]ROT-Tree Rotations(线段树合并)
题意:给定一颗有 n 个叶节点的二叉树.每个叶节点都有一个权值pi(注意,根不是叶节点),所有叶节点的权值构成了一个1∼n 的排列.对于这棵二叉树的任何一个结点,保证其要么是叶节点,要么左右两个孩子 ...
- Java8新特性之FlatMap&Reduce
1.FlagMap // flatMap:接收一个T返回一个R,将一个元素转为一个新的流 ;R apply(T t); <R> Stream<R> flatMap(Functi ...
- Javascript Ajax总结——其他跨域技术之图像Ping和JSONP
在CORS出现之前,为实现跨域Ajax通信,开发人员利用DOM中能够执行跨域请求的功能,在不依赖XHR对象的情况下也能发送某种请求.1.图像Ping这里使用<img>标签.一个网页可以从任 ...
- CentOS系统中yum的基本用法
最小化安装系统时,yum可能会因为网卡配置问题,随机启动配置,导致无法使用, 在shell里面输入:yum --help ,结果显示 yum 已经正常安装了!!到底是哪里出了问题呢?经过网友的提示,我 ...
- gsamplerCubeArrayShadow isn't supported in textureGrad, textureLod or texture with bias
问题描述 跑rust的Bevy示例程序 运行3d的示例,cargo run --example 3d_shapes 发现报错: INFO bevy_render::renderer: AdapterI ...
- 通过JDK动态代理类实现一个类中多种方法的不同增强
1.为什么说JDK动态代理必须要实现当前父接口才能使用 JDK动态代理是基于接口的代理,它要求目标类(被代理的类)必须实现一个或多个接口.这是因为JDK动态代理是通过创建目标类的接口的代理对象来实现的 ...
- 未能加载文件或程序集“*****.dll”或它的某一个依赖项。找到的程序集清单定义与程序集引用不匹配。(异常来自HRESULT:0x80131040)
问题描述: 未能加载文件或程序集"*****.dll"或它的某一个依赖项.找到的程序集清单定义与程序集引用不匹配.(异常来自HRESULT:0x80131040) 解决方法: 1. ...
- Java 中时间对象的序列化
在 Java 应用程序中,时间对象是使用地比较频繁的对象,比如,记录某一条数据的修改时间,用户的登录时间等应用场景.在传统的 Java 编程中,大部分的程序员都会选择使用 java.uti.Date ...