使用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(); } } }
缺陷:遮不住視頻
效果圖: