☰
Avalonia Canvas 画仪表盘:3 段 XAML,0 行 C
2026/10/21 13:54:52 网站建设 项目流程

Avalonia Canvas 画仪表盘:3 段 XAML,0 行 C#

【免费下载链接】AvaloniaDevelop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The future of .NET UI项目地址: https://gitcode.com/GitHub_Trending/ava/Avalonia

用 Avalonia 里的一个 Canvas 加四种基础图形,做出一个带刻度、指针和读数的速度仪表盘。不写一行 C#,不装任何额外依赖,XAML 粘进任意窗口就能跑。

先弄清 3 件事

  • 入口控件在哪:画板是Canvas,实现在 Canvas.cs;直线、矩形、椭圆、路径这四种图形都放在 Shapes 目录里。
  • 原点和方向:画板左上角是原点 (0,0),x 向右增大、y 向下增大,和数学课的坐标系反着来。150,150就是"向右 150、向下 150"。
  • 单位是 DIP:DIP 即设备无关像素(跨平台统一的"虚拟像素"),支持小数,比如27.5。同一份 XAML 在 Windows、macOS、Linux 上渲染一致。
  • Canvas 不做布局:它不给子元素自动排列,测量时自己报 0,0 大小,所以能叠在任何面板上当绘图层。但反过来,坐标不钉住,子元素全堆在左上角。

核心机制:一个比喻讲透

Canvas 像一块贴在窗口上的透明玻璃。玻璃本身没花纹、不占布局空间,可以盖在任何面板上当绘图层。每个子控件是一张贴纸,用Canvas.Left/Top手动按在玻璃某个位置。两张贴纸重叠时谁在上?不是谁先贴的算,而是ZIndex说了算,数字大的在前。这个属性定义在 Visual.cs,所有图形都能用。

说白了,Canvas 只回答一个问题:"在这个坐标上画什么"。表盘、刻度、指针全是几何图形,渲染器按 ZIndex 顺序遍历:用Stroke描边,用Fill填充内部。换个说法,XAML 负责"画什么",Canvas 负责"画在哪",ZIndex 负责"谁在前"。

上面是仓库里的一张几何渲染测试图,两条弧线和表盘一样,走的都是"几何图形 + 填充/描边"这套机制。

API 速查(一张表搞定)

名称干什么填什么值
Canvas.Left/Canvas.Top钉住元素左边、上边位置像素数,50
Canvas.Right/Canvas.Bottom从右、下边缘反向锚定,适合"贴底"元素像素数,50
StartPoint/EndPointLine 的两个端点点,150,150
Stroke/StrokeThickness轮廓颜色、粗细Black、2
Fill/RadiusX/RadiusY内部颜色、圆角半径Red、12
Data(仅 Path)任意轮廓命令串M 50,100 L 150,100 Z
Canvas.ZIndex叠放层次,大的在上整数,1
Text(TextBlock)读数文字60 km/h

Left 和 Right 同时设时 Left 生效,Top 和 Bottom 同设时 Top 生效。你可能会问为什么不让两边平均一下——避免歧义,每个方向只认一个。Data记住四个命令就够:M移动画笔、L画直线、C贝塞尔曲线、Z闭合,闭合后Fill才会填整个区域。

从 0 到能跑:三段递进

照常新建一个 Avalonia 应用(官方模板依赖都配好了),把MainWindow.axaml里 Window 的内容换成下面每一段的 Canvas,就能直接看效果。每段代码都是完整画板,不用拼。八条刻度的坐标不是瞎编:表盘中心 (150,150),刻度半径 125,0° 方向就是 (150,25);45° 方向 125×0.707≈88,所以拐角在 (239,61),其余六个点照此对称。

铺底 + 打刻度

这一段只画静态部分:两个椭圆做出表盘,八条线打出刻度。画到这儿,仪表盘已经占了一半。

<!-- 外灰内白:两个椭圆自然形成环形边框,省掉描边 --> <Canvas Width="300" Height="300"> <Ellipse Canvas.Left="20" Canvas.Top="20" Width="260" Height="260" Fill="#D3D3D3"/> <Ellipse Canvas.Left="28" Canvas.Top="28" Width="244" Height="244" Fill="White"/> <!-- 刻度起点贴边、终点朝内收 15 像素,比一整圈实线更好认 --> <Line StartPoint="150,25" EndPoint="150,40" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="239,61" EndPoint="228,72" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="275,150" EndPoint="260,150" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="239,239" EndPoint="228,228" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="150,275" EndPoint="150,260" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="61,239" EndPoint="72,228" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="25,150" EndPoint="40,150" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="61,61" EndPoint="72,72" Stroke="Black" StrokeThickness="2"/> </Canvas>

插一根会转的针

这一步比上一段多了两个元素:从中心伸到表盘边缘的红针,和盖住针尾的中心红点。两者都用 ZIndex 显式声明层次,后面无论怎么挪位置都不会被刻度压住。指针指向 (210,85),角度大约 35°,正好对应后面 60 km/h 的读数;指针朝哪都行,它就是一根线段。

<Canvas Width="300" Height="300"> <Ellipse Canvas.Left="20" Canvas.Top="20" Width="260" Height="260" Fill="#D3D3D3"/> <Ellipse Canvas.Left="28" Canvas.Top="28" Width="244" Height="244" Fill="White"/> <Line StartPoint="150,25" EndPoint="150,40" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="239,61" EndPoint="228,72" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="275,150" EndPoint="260,150" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="239,239" EndPoint="228,228" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="150,275" EndPoint="150,260" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="61,239" EndPoint="72,228" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="25,150" EndPoint="40,150" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="61,61" EndPoint="72,72" Stroke="Black" StrokeThickness="2"/> <!-- 指针:中心 (150,150) 到边缘,ZIndex=1 保证压在刻度之上 --> <Line StartPoint="150,150" EndPoint="210,85" Stroke="Red" StrokeThickness="4" Canvas.ZIndex="1"/> <!-- 中心红点盖住针尾汇聚处,ZIndex=2 提到最前 --> <Ellipse Canvas.Left="142" Canvas.Top="142" Width="16" Height="16" Fill="Red" Canvas.ZIndex="2"/> </Canvas>

贴上数字标签

最后一步只多一行:表盘下方放一个TextBlock显示速度。文字和图形互不干扰,它在 Canvas 眼里也只是又一个子元素。

<Canvas Width="300" Height="300"> <Ellipse Canvas.Left="20" Canvas.Top="20" Width="260" Height="260" Fill="#D3D3D3"/> <Ellipse Canvas.Left="28" Canvas.Top="28" Width="244" Height="244" Fill="White"/> <Line StartPoint="150,25" EndPoint="150,40" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="239,61" EndPoint="228,72" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="275,150" EndPoint="260,150" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="239,239" EndPoint="228,228" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="150,275" EndPoint="150,260" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="61,239" EndPoint="72,228" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="25,150" EndPoint="40,150" Stroke="Black" StrokeThickness="2"/> <Line StartPoint="61,61" EndPoint="72,72" Stroke="Black" StrokeThickness="2"/> <!-- 指针与中心点:ZIndex 锁住层次,指针不会掉到刻度下面 --> <Line StartPoint="150,150" EndPoint="210,85" Stroke="Red" StrokeThickness="4" Canvas.ZIndex="1"/> <Ellipse Canvas.Left="142" Canvas.Top="142" Width="16" Height="16" Fill="Red" Canvas.ZIndex="2"/> <!-- 读数:放在表盘下方,文字只是 Canvas 的又一个子元素 --> <TextBlock Canvas.Left="120" Canvas.Top="285" Text="60 km/h" FontSize="14"/> </Canvas>

到这儿仪表盘成型了:椭圆、直线、红点、文字四种元素,加上两层 ZIndex,静态部分齐活。

新手最常翻车的 3 个点

这三个坑最多人栽,看一行就能避开。

不写坐标,子元素叠成一层

❌<Ellipse Width="80" Height="80" Fill="Red"/>✅<Ellipse Canvas.Left="50" Canvas.Top="50" Width="80" Height="80" Fill="Red"/>

Canvas 不做布局,Left/Top 缺了,所有子元素全堆在原点 (0,0),看起来像"没渲染"。

Left 和 Right 同设,Right 被忽略

❌<Rectangle Canvas.Left="50" Canvas.Right="50" Width="100"/>✅<Rectangle Canvas.Left="50" Width="100"/>

同设时 Left 生效、Right 直接无视,Top 和 Bottom 同理。每个方向只写一个。

靠 XAML 顺序调层次,一挪全乱

❌ 把指针挪到刻度前面一行,结果指针被刻度盖住 ✅ 指针显式加Canvas.ZIndex="1"

默认"后写的在上",但元素一旦移动,顺序就跟着乱了,重要层次用 ZIndex 钉死。

下一步能玩什么

  • 给指针挂上RotateTransform,用DoubleAnimation驱动AngleProperty改角度,仪表盘指针就能随读数真实摆动;这条能力只管转,图形大小不变。
  • 把Slider的Value绑到某个图形的Width和Height,拖动滑块看几何实时变化,这就是数据驱动图形的入口。

仪表盘到这里就算跑通了。坐标系、层次、绑定这几套机制,在 Avalonia 其他控件上完全通用,这套 Canvas 经验可以整个带走。

【免费下载链接】AvaloniaDevelop Desktop, Embedded, Mobile and WebAssembly apps with C# and XAML. The future of .NET UI项目地址: https://gitcode.com/GitHub_Trending/ava/Avalonia

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询