如何在 VisualBrush 上设置 ViewPort 和 ViewBox 以在 WPF Canvas 中创建虚线背景?

How to set ViewPort and ViewBox on a VisualBrush to create a dotted background in a WPF Canvas?

我想创建一个带有对齐网格的 Canvas。我实现了将我的对象捕捉到视图模型中的 20 像素网格的逻辑,现在我正在处理视图。我希望网格看起来像这样:

我想到了这个解决方案,但我不喜欢它,似乎有点乱(它使用 4 个对象而不是 1 个对象作为模式,这会影响性能吗?)。

<Canvas.Background>
    <VisualBrush TileMode="Tile" Viewport="0,0,20,20" ViewportUnits="Absolute" Viewbox="0,0,20,20" ViewboxUnits="Absolute">
        <VisualBrush.Visual>
            <Grid Width="20" Height="20">
                <Ellipse Height="2" Width="2" Stroke="Black" StrokeThickness="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="-1,-1"/>
                <Ellipse Height="2" Width="2" Stroke="Black" StrokeThickness="1" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="-1,-1"/>
                <Ellipse Height="2" Width="2" Stroke="Black" StrokeThickness="1" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="-1,-1"/>
                <Ellipse Height="2" Width="2" Stroke="Black" StrokeThickness="1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="-1,-1"/>
            </Grid>
        </VisualBrush.Visual>
    </VisualBrush>
</Canvas.Background>

问题是,如果我只使用一个 Ellipse,没有像这样的负边距:

<Canvas.Background>
    <VisualBrush TileMode="Tile" Viewport="0,0,20,20" ViewportUnits="Absolute" Viewbox="0,0,20,20" ViewboxUnits="Absolute">
        <VisualBrush.Visual>
            <Grid Width="20" Height="20">
                <Ellipse Height="2" Width="2" Stroke="Black" StrokeThickness="1" HorizontalAlignment="Left" VerticalAlignment="Top" />
            </Grid>
        </VisualBrush.Visual>
    </VisualBrush>
</Canvas.Background>

椭圆中心点偏移1px:


如果我添加 -1px 偏移量:

<Canvas.Background>
    <VisualBrush TileMode="Tile" Viewport="0,0,20,20" ViewportUnits="Absolute" Viewbox="0,0,20,20" ViewboxUnits="Absolute">
        <VisualBrush.Visual>
            <Grid Width="20" Height="20">
                <Ellipse Height="2" Width="2" Stroke="Black" StrokeThickness="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="-1,-1" />
            </Grid>
        </VisualBrush.Visual>
    </VisualBrush>
</Canvas.Background>

3/4 的点在背景图块之外:


我想我可以把点放在网格的中间,但是我必须更改我的视图模型计算并添加一个偏移量 - 我认为它比第一个视图更大 "hack"。

我怀疑应该有一些使用 ViewPortViewBox 的解决方法,但我还不太了解它们。

请给我最简单的解决方案,将我的背景设置为点捕捉网格,在 20px 网格中有点,没有偏移。 (例如,点以 (0,0) (0,20) (20,0) (20,20) 等为中心)


编辑:这应该足以重现矩形和控件:

<Canvas>
    <Canvas.Background>
        <VisualBrush TileMode="Tile" Viewport="0,0,20,20" ViewportUnits="Absolute" Viewbox="0,0,20,20" ViewboxUnits="Absolute">
            <VisualBrush.Visual>
                <Grid Width="20" Height="20">
                    <Ellipse Height="2" Width="2" Stroke="Black" StrokeThickness="1" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="-1,-1" />
                    <Ellipse Height="2" Width="2" Stroke="Black" StrokeThickness="1" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="-1,-1"/>
                    <Ellipse Height="2" Width="2" Stroke="Black" StrokeThickness="1" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="-1,-1"/>
                    <Ellipse Height="2" Width="2" Stroke="Black" StrokeThickness="1" HorizontalAlignment="Right" VerticalAlignment="Bottom" Margin="-1,-1"/>
                </Grid>
            </VisualBrush.Visual>
        </VisualBrush>
    </Canvas.Background>
    <Canvas.Children>
        <Rectangle Canvas.Left="40" Canvas.Top="40" Width="100" Height="80" Fill="Yellow" Stroke="blue" />
    </Canvas.Children>
</Canvas>

将您的 ViewportViewbox 都设置为 -1 -1 20 20"。它将显示如下:

ViewBox表示你想取VisualBrush的哪一部分,所以你必须从-1 -1开始,否则你拿不到左上角的部分因为你的负面圈子 Margin.

ViewPort 表示第一个图块在 Canvas 背景中的位置。同样,您希望它在 -1 -1 处将圆心与 Canvas.

的原点对齐

对于简单的绘图,最好使用 DrawingBrush 而不是 VisualBrush:

<DrawingBrush TileMode="Tile"
              Viewport="-10,-10,20,20" ViewportUnits="Absolute"
              Viewbox="-10,-10,20,20" ViewboxUnits="Absolute">
    <DrawingBrush.Drawing>
        <GeometryDrawing Brush="Black">
            <GeometryDrawing.Geometry>
                <EllipseGeometry RadiusX="1" RadiusY="1"/>
            </GeometryDrawing.Geometry>
        </GeometryDrawing>
    </DrawingBrush.Drawing>
</DrawingBrush>