ウォーターマークデコレータ 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">マージン</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();
}
}
}
効果図:

「iSlide」というPPTプラグインがあります。そのWindowsクライアントはWPFで開発されており、PPTパズル機能があります。その中のウォーターマーク機能は上記と同様のコードを使用しています。効果を見てこの記事を終えましょう:
