0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【UWP】点線を敷き詰めて表示しよう【タイル描画】

Posted at

ひとまず完成イメージがこちら

image.png

image.png

画像中の点線表示機能のみこの記事で紹介し、それ以外は開発中アプリ固有のUIのため触れません

画像ベースのタイル描画はTileControlが適する

既製のものとして、TileControlも選択肢です。

ただしTileControl.ImageSourceはUriを要求し画像ファイルが必要なため、ランタイム中に画像を生成するような動的に点線を表示したい場合には適しません。

カスタムなタイル描画にCanvasControlを利用するコード例

ページ先頭の画像のXaml構成はざっくりこんな感じです

  • Grid
    • アプリ固有の描き込みエリア
      • RenderTransform に LateUpdateCanvasTransform を保有
    • 点線を表示するCanvasControl

アプリ固有の描き込みエリアは縦横ともにCenter表示、点線表示のCanvasControlは親GridにStretch表示しています。

private void SnapGridCanvasControl_Draw(CanvasControl sender, CanvasDrawEventArgs args)
{
    using var list = new CanvasCommandList(sender);
    using var session = list.CreateDrawingSession();

    var canvasSize = _vm.EpisodeContext!.DefaultCanvasSize.ToVector2();
    var transform = LateUpdateCanvasTransform;
    float invScale = 1f / (float)LateUpdateCanvasTransform.ScaleX;
    Vector2 translate = new Vector2( MathF.Round((float)transform.TranslateX), MathF.Round((float)transform.TranslateY));

    float strokeWidth = 1f * invScale;
    float strokeWidthHalf = strokeWidth * 0.5f;
    float strokeX = canvasSize.X * 0.25f;
    float strokeY = canvasSize.Y * 0.25f;

    DrawDashedLine(session, new Vector2(strokeWidthHalf, strokeWidthHalf), new Vector2(strokeX, strokeWidthHalf), Colors.Black, strokeWidth, CanvasDashStyle.Dash);
    DrawDashedLine(session, new Vector2(strokeWidthHalf, strokeWidthHalf), new Vector2(strokeWidthHalf, strokeY), Colors.Black, strokeWidth, CanvasDashStyle.Dash);

    using var tile = new TileEffect()
    {
        Source = list,
        SourceRectangle = new Rect(0, 0, strokeX, strokeY),
    };
    
    using var crop = new CropEffect()
    {
        Source = tile,
        SourceRectangle = new Rect(0, 0, sender.ActualSize.X * 1000, sender.ActualSize.Y * 1000),
    };

    // タイル用CanvasControlは左上が原点
    // キャンバスは画面中央が原点
    // キャンバスの変形に応じて表示しつつ、タイル用CanvasControlの原点がキャンバスの左上となるよう
    // 中央への移動とキャンバス原点への移動で二段階している
    args.DrawingSession.Transform =
        Matrix3x2.CreateTranslation(-canvasSize * 0.5f)
        * Matrix3x2.CreateScale((float)transform.ScaleX, (float)transform.ScaleY)
        * Matrix3x2.CreateRotation((float)transform.Rotation)
        * Matrix3x2.CreateTranslation(translate)
        * Matrix3x2.CreateTranslation(sender.ActualSize * 0.5f);
    // draw the effect (using bitmap as input)
    args.DrawingSession.DrawImage(crop);
}

/// <summary>
/// CanvasDrawingSession に破線を描画します。
/// </summary>
private void DrawDashedLine(
    CanvasDrawingSession ds, 
    Vector2 p1,
    Vector2 p2, 
    Color color, 
    float strokeWidth = 1f,
    CanvasDashStyle dashStyle = CanvasDashStyle.Dash, 
    float dashOffset = 0f,
    float[]? customDash = null)
{
    using var stroke = new CanvasStrokeStyle()
    {
        DashStyle = customDash is null ? dashStyle : CanvasDashStyle.DashDot,
        DashOffset = dashOffset,
        EndCap = CanvasCapStyle.Round,
        DashCap = CanvasCapStyle.Round,
        LineJoin = CanvasLineJoin.Round,
    };

    if (customDash != null)
    {
        stroke.CustomDashStyle = customDash;
    }

    ds.DrawLine(p1, p2, color, strokeWidth, stroke);
}

参考

CanvasControl

CanvasControlを利用すると配置したXamlの親要素にStretchされた状態で描写できて便利です。

CanvasControl.Drawイベントにフックすると描写範囲の指定されたCanvasDrawingSessionが渡されます。

TileEffect

Sourceに指定した描画処理を繰り返し表示できるエフェクトです。

CropEffect

SourceRectangleに指定した範囲で描画処理範囲をくり抜きます。サイズ変更可能な方向にのみ点線を表示したいので表示範囲を制限するために利用します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?