GridOverlay.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Shapes;
namespace Maywork.WPF.Helpers;
public static class GridOverlay
{
// =========================
// Enable
// =========================
public static readonly DependencyProperty EnableProperty =
DependencyProperty.RegisterAttached(
"Enable",
typeof(bool),
typeof(GridOverlay),
new PropertyMetadata(false, OnEnableChanged));
public static void SetEnable(DependencyObject obj, bool value)
=> obj.SetValue(EnableProperty, value);
public static bool GetEnable(DependencyObject obj)
=> (bool)obj.GetValue(EnableProperty);
// =========================
// Step
// =========================
public static readonly DependencyProperty StepProperty =
DependencyProperty.RegisterAttached(
"Step",
typeof(double),
typeof(GridOverlay),
new PropertyMetadata(50.0, OnPropertyChanged));
public static void SetStep(DependencyObject obj, double value)
=> obj.SetValue(StepProperty, value);
public static double GetStep(DependencyObject obj)
=> (double)obj.GetValue(StepProperty);
// =========================
// Stroke
// =========================
public static readonly DependencyProperty StrokeProperty =
DependencyProperty.RegisterAttached(
"Stroke",
typeof(Brush),
typeof(GridOverlay),
new PropertyMetadata(Brushes.White, OnPropertyChanged));
public static void SetStroke(DependencyObject obj, Brush value)
=> obj.SetValue(StrokeProperty, value);
public static Brush GetStroke(DependencyObject obj)
=> (Brush)obj.GetValue(StrokeProperty);
// =========================
// StrokeThickness
// =========================
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.RegisterAttached(
"StrokeThickness",
typeof(double),
typeof(GridOverlay),
new PropertyMetadata(1.0, OnPropertyChanged));
public static void SetStrokeThickness(DependencyObject obj, double value)
=> obj.SetValue(StrokeThicknessProperty, value);
public static double GetStrokeThickness(DependencyObject obj)
=> (double)obj.GetValue(StrokeThicknessProperty);
// =========================
// 内部管理
// =========================
private static readonly DependencyProperty PathProperty =
DependencyProperty.RegisterAttached(
"PathInternal",
typeof(Path),
typeof(GridOverlay));
private static void SetPath(DependencyObject obj, Path? value)
=> obj.SetValue(PathProperty, value);
private static Path? GetPath(DependencyObject obj)
=> (Path?)obj.GetValue(PathProperty);
// =========================
// Enable変更
// =========================
private static void OnEnableChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is not Canvas canvas) return;
if ((bool)e.NewValue)
{
var path = new Path
{
IsHitTestVisible = false
};
Panel.SetZIndex(path, int.MaxValue);
SetPath(canvas, path);
canvas.Children.Add(path);
canvas.SizeChanged += OnSizeChanged;
Update(canvas);
}
else
{
var path = GetPath(canvas);
if (path != null)
{
canvas.Children.Remove(path);
SetPath(canvas, null);
}
canvas.SizeChanged -= OnSizeChanged;
}
}
// =========================
// プロパティ変更
// =========================
private static void OnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Canvas canvas && GetEnable(canvas))
{
Update(canvas);
}
}
private static void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
if (sender is Canvas canvas)
{
Update(canvas);
}
}
// =========================
// 更新処理
// =========================
private static void Update(Canvas canvas)
{
var path = GetPath(canvas);
if (path == null) return;
double width = canvas.ActualWidth;
double height = canvas.ActualHeight;
double step = GetStep(canvas);
if (width <= 0 || height <= 0 || step <= 0) return;
path.Data = CreateGridGeometry(width, height, step);
path.Stroke = GetStroke(canvas);
path.StrokeThickness = GetStrokeThickness(canvas);
}
// =========================
// Geometry生成
// =========================
private static Geometry CreateGridGeometry(double width, double height, double step)
{
var geo = new StreamGeometry();
using (var ctx = geo.Open())
{
// 縦線
for (double x = 0; x <= width; x += step)
{
ctx.BeginFigure(new Point(x, 0), false, false);
ctx.LineTo(new Point(x, height), true, false);
}
// 横線
for (double y = 0; y <= height; y += step)
{
ctx.BeginFigure(new Point(0, y), false, false);
ctx.LineTo(new Point(width, y), true, false);
}
}
geo.Freeze();
return geo;
}
}
/*
// 使用例
<Canvas
h:GridOverlay.Enable="True"
h:GridOverlay.Step="50"
h:GridOverlay.Stroke="#FF0000"
h:GridOverlay.StrokeThickness="1">
<Image x:Name="MyImage" />
</Canvas>
*/
Download

コメント