I am learning Avalonia for a small project and I really enjoy it, but I can't find much documentation on drawing in a canvas.
My goal is very simple: to draw a grid on my canvas...
However, every time I try, nothing shows up. Even though the lines are being called when I place breakpoints, I am a bit lost.
I created this example to illustrate:
public partial class Tests : UserControl, IInterface
{
private double gridSize = 2;
private SolidColorBrush gridBrush = new SolidColorBrush(Colors.Black);
public Tests()
{
InitializeComponent();
gridCanvas.InvalidateVisual();
}
public override void Render(DrawingContext context)
{
base.Render(context);
DrawGrid(context);
}
private void DrawGrid(DrawingContext context)
{
var canvasWidth = gridCanvas.Bounds.Width;
var canvasHeight = gridCanvas.Bounds.Height;
var pen = new Pen(Brushes.Black, thickness: 20); // Adjust thickness if necessary
for (double x = 0; x < canvasWidth; x += gridSize)
{
context.DrawLine(pen, new Point(x, 0), new Point(x, canvasHeight));
}
for (double y = 0; y < canvasHeight; y += gridSize)
{
context.DrawLine(pen, new Point(0, y), new Point(canvasWidth, y));
}
}
}
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="AvaloniaTest.Tests">
<Canvas Name="gridCanvas" Background="Beige">
<Rectangle Fill="Red" Canvas.Left="10" Canvas.Top="10" Width="5" Height="5"/>
</Canvas>
</UserControl>
In this example, I can see my red rectangle in the top left corner and the beige background, but not the grid. Can someone explain why?
Thanks in advance, and have a nice day.
As mentioned by Jeroen van Langen, your problem is you are drawing to the UserControl drawing context. You could use Lines and add them to the Canvas.
Line line = new()
{
// Setup.
};
gridCanvas.Children.Add(line);
However, Be aware that Line is a Shape (Avalonia.Controls.Shapes). Shapes are controls, that is they inherit Control. This means they have a lot of overhead you may not need in order to allow them to function as a control. This is OK if you need control functionality, such as the ability to move them around dynamically, but if all you need is a static drawing and especially if you would otherwise need a large number of shapes, this can be resource costly.
However, you can render a DrawingContext to a Control (or any visual where the Render isn't sealed). Unfortunately we don't have a DrawingVisual.RenderOpen option like WPF to grab a DrawingContext. Instead you will have to create a class that derives from Control and override Render on that object.
public class DrawingCanvas : Control
{
// Constructors and stuff
public override void Render(DrawingContext context)
{
base.Render(context);
// Draw here.
}
}
You may also need to call InvalidateVisual()
to render.
To include this on your view, just add a local namespace:
xmlns:local="clr-namespace=AvaloniaTest"
And preface the name in xaml:
<local:DrawingCanvas/>