In GDI+ one can draw directly onto the canvas (create an in-memory bitmap and do whatever needs to be done there).
I need the same for Avalonia for 'custom controls' and I was informed that that is possible since access is available to SkiaSharp.Canvas
. Can anyone give some clues on how to do this?
An example would be a continuous changing curve like for instance the voice frequency. If you do not do this directly on a canvas (or whatever it is named in the Xaml-world), it is too slow and takes too many resources, especially if you need 10 to 20 of these on one screen.
I have a background in GDI+, JavaFX, QML but I'm pretty new in Xaml-land. I have read the complete Avalonia documentation, but nothing in that direction. I understand other priorities are in place at this stage of the Avalonia-project.
I took the 'LineBoundsDemoControl' from the 'RenderDemo' frankenapps refered to in the comments, as the answer to my question.
The actual drawing happens in the 'Render' method on the 'drawingContext'. It looks a lot like GDI+ with the pen and brush.
If you are new to Avalonia/xaml, like myself, the static constructor with the 'AffectsRender' in it will probably be the weirdest. According to the Avalonia source code this method indicates that a property change should cause an invalidation (redraw) of the control. Learning all the time ...
This method should be called in a control's static constructor with each property on the control which when changed should cause a redraw. This is similar to WPF's FrameworkPropertyMetadata.AffectsRender flag.
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
using Avalonia.Rendering.SceneGraph;
using Avalonia.Threading;
namespace RenderDemo.Controls
{
public class LineBoundsDemoControl : Control
{
static LineBoundsDemoControl()
{
AffectsRender<LineBoundsDemoControl>(AngleProperty);
}
public LineBoundsDemoControl()
{
var timer = new DispatcherTimer();
timer.Interval = TimeSpan.FromSeconds(1 / 60.0);
timer.Tick += (sender, e) => Angle += Math.PI / 360;
timer.Start();
}
public static readonly StyledProperty<double> AngleProperty =
AvaloniaProperty.Register<LineBoundsDemoControl, double>(nameof(Angle));
public double Angle
{
get => GetValue(AngleProperty);
set => SetValue(AngleProperty, value);
}
public override void Render(DrawingContext drawingContext)
{
var lineLength = Math.Sqrt((100 * 100) + (100 * 100));
var diffX = LineBoundsHelper.CalculateAdjSide(Angle, lineLength);
var diffY = LineBoundsHelper.CalculateOppSide(Angle, lineLength);
var p1 = new Point(200, 200);
var p2 = new Point(p1.X + diffX, p1.Y + diffY);
var pen = new Pen(Brushes.Green, 20, lineCap: PenLineCap.Square);
var boundPen = new Pen(Brushes.Black);
drawingContext.DrawLine(pen, p1, p2);
drawingContext.DrawRectangle(boundPen, LineBoundsHelper.CalculateBounds(p1, p2, pen));
}
}
}