AvaloniaUI control with custom rendering
In order to draw some custom graphics on a control we can use Skiasharp library, which is bundled with Avalonia as a dependency. First, we need to create a class for our new control. We’ll use a snippet from one of the AvaloniaUI devs - Nikita Tsukanov (src).
namespace MyApp.CustomControls
{
public class CustomControl : UserControl
{
class CustomDrawOp :ICustomDrawOperation
{
private readonly IImmutableGlyphRunReference? _noSkia;
private SKCanvas? _canvas;
public CustomDrawOp(Rect Bounds, GlyphRun noSkia)
{
_noSkia = noSkia.TryCreateImmutableGlyphRunReference();
Bounds = bounds;
}
public void Dispose()
{
// Dispose whatever were added to control
}
public Rect Bounds {get; }
public bool HitTest (Point p) => true;
public bool Equals (ICustomDrawOperation? other) => false;
public void Render(ImmediateDrawingContext context)
{
var leaseFeature = context.TryGetFeature<ISkiaSharpApiLeaseFeature>();
if (leaseFeature == null)
{
context.DrawGlyphRun(Brush.Parse("#000000").ToImmutable(), _noSkia!);
}
else
{
using var lease = leaseFeature.Lease();
_canvas = lease.SkCanvas;
_canvas.Clear(SKColor.Parse("#00000000"));
// ... draw anything with SkiaSharp on _canvas
_canvas.Restore();
}
}
}
public override void Render(DrawinngContext context)
{
context.Custom(new CustomDrawOp(new Rect(0, 0, Bounds.Width, Bounds.Height), _noSkia);
Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background);
}
}
}
Most likely our control has to visualize some data from the ViewModel. Let’s use bindings mechanism for that:
public static readonly DirectProperty<IntegrityView, IEnumerable<int>> XProperty =
AvaloniaProperty.RegisterDirect<IntegrityView, IEnumerable<int>>(
nameof(X),
o => o.X,
(o, v) => o.X = v);
private IEnumerable<int> _x = new AvaloniaList<int>();
public IEnumerable<int> X
{
get => _x;
set => SetAndRaise(XProperty, ref _x, value);
}
Now we can bind a property from the ViewModel to the UserControl and render things there. It’s time to actually use the control:
Add the reference to our control to the View, which will be using it:
xmlns:cc="using:MyApp.CustomControls"
And add the control to the markup, binding some data from the ViewModel:
<cc:CustomControl
X="{Binding XValues}" />