WPF Demo - 水印控件

199 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情

阅读本文大概需要 5 分钟

前言

甲方提了个需求,要求应用上加上水印。

水印中文字的排布比较有规律,想出了两个方案

  1. 使用网格布局,在特定的位置填入水印文字
  2. Canvas 自己画文字

代码实现

使用网格布局

image.png

新建一个 UserControl,因为水印的特性,我们选择继承 UniformGrid,这样添加元素简单方便。

public class WatermarkControl : UniformGrid
{
    public WatermarkControl()
    {
        // 初始化参数
        InitDefaultParams();
        // 初始化水印内容,并添加到布局中
        InitWatermarkContent();
        // 初始化旋转角度
        InitRotate();
    }
}

因为这种方法可控性不强,且旋转的时候不太好看,最终没有采用该方法,感兴趣的朋友可以通过文末的 Gitee 地址自行查看

自己 Canvas 画

项目最终用了这种方法,灵活的一批。 总共分为以下几个部分

  1. 设置水印透过点击事件
  2. 计算控件的宽高,用于后续写字
  3. 计算水印文字的宽度,用于计算下一个文字的偏移量
  4. 一个循环,遍历画水印文字

成品的使用方法,可以自定义以下属性:

  • FontSize
  • Angle
  • Foreground
  • Text
  • row space
  • column space
<Grid>
    <!--... layout yourself-->
    <local:WatermarkCanvas x:Name="watermarkCanvas"
            WatermarkFontSize="14"
            WatermarkAngle="-15"
            WatermarkForeground="#6666"
            WatermarkText="Hello&#13;BigFlowerFat" 
            WatermarkTextWidthSpaceMultiple="2"
            WatermarkTextHeightSpaceMultiple="8"/>
</Grid>

1. 水印透过点击事件

// 初始化默认参数让
private void InitDefaultParams()
{
    // 因为水印要覆盖到界面上层,所以需要让水印能透过鼠标点击
    this.IsHitTestVisible = false;
}

2. 界面渲染时,获取基本参数

protected override void OnRender(DrawingContext drawingContext)
{
    // 获取该控件的基本参数:宽、高、文字占用的宽度
    InitSizeParams();
    // 画水印文字
    DrawTexts(drawingContext);
}

3. 画水印文字

image.png

画水印文字就比较简单了,先算出 水印有多少列 = 布局宽度 / 文字宽度,然后循环画就完了。使用方法也很简单 DrawText(文字,坐标)

drawingContext.DrawText(ft, point);
/// <summary>
/// draw the watermark text
/// </summary>
/// <param name="drawingContext"></param>
private void DrawTexts(DrawingContext drawingContext)
{
    // rotate 旋转
    drawingContext.PushTransform(new RotateTransform(WatermarkAngle, 0, 0));
    FormattedText ft = new FormattedText(WatermarkText,
                            CultureInfo.InvariantCulture,
                            FlowDirection.LeftToRight,
                            new Typeface(WatermarkFontFamily),
                            WatermarkFontSize, WatermarkForeground);
    // calculate the the text's row and column number 根据文字宽高、布局宽高,计算要画多少个水印字
    int rowNumber = (int)(mHeight / WatermarkFontSize / 10) + 5;
    int columnNumber = (int)(mWidth / mTextWidth) + 2;
    // draw text 写字
    for (int row = -5; row < rowNumber; row++)
    {
            for (int column = -1; column < columnNumber; column++)
            {
                    // Stagger adjacent rows
                    double offset = row % 2 == 0 ? 0 : mTextWidth / 2;
                    Point point = new Point(mTextWidth * column - offset, WatermarkFontSize * row * WatermarkTextHeightSpaceMultiple);
                    drawingContext.DrawText(ft, point);
        }
    }
}

后记

文章代码已经上传到 gitee.com/bigflowerfa…

该项目中也还有其他有意思的 Demo

Screenshot.gif

Animation.gif