I had trouble figuring this out using other answers on this site, so hopefully this helps others.
The idea is that any control has an overridable Render method. This method can call context.Custom
which takes an ICustomDrawOperation
instance. My understanding is that Skia rendering is not guaranteed, so the code needs to check and cast to a ISkiaDrawingContextImpl
.
For those who just want to drop something in (like I did), here's some code that should help:
public partial class SkiaCanvas : UserControl
{
class RenderingLogic : ICustomDrawOperation
{
public Action<SKCanvas> RenderCall;
public Rect Bounds { get; set; }
public void Dispose() {}
public bool Equals(ICustomDrawOperation? other) => other == this;
// not sure what goes here....
public bool HitTest(Point p) { return false; }
public void Render(IDrawingContextImpl context)
{
var canvas = (context as ISkiaDrawingContextImpl)?.SkCanvas;
if(canvas != null)
{
Render(canvas);
}
}
private void Render(SKCanvas canvas)
{
RenderCall?.Invoke(canvas);
}
}
RenderingLogic renderingLogic;
public event Action<SKCanvas> RenderSkia;
public SkiaCanvas()
{
InitializeComponent();
renderingLogic = new RenderingLogic();
renderingLogic.RenderCall += (canvas) => RenderSkia?.Invoke(canvas);
}
public override void Render(DrawingContext context)
{
renderingLogic.Bounds = new Rect(0, 0, this.Bounds.Width, this.Bounds.Height);
context.Custom(renderingLogic);
// If you want continual invalidation (like a game):
//Dispatcher.UIThread.InvokeAsync(InvalidateVisual, DispatcherPriority.Background);
}
}
Now you can drop the skia canvas in your own AXAML:
<views:SkiaCanvas Height="200" RenderSkia="HandleRenderSkia"></views:SkiaCanvas>
Implement the HandleRenderSkia in your codebehind:
void HandleRenderSkia(SKCanvas canvas)
{
canvas.DrawCircle(100, 100, 80, new SKPaint() { Color = SKColors.Green, IsAntialias = true });
}
Now you'll have full skia rendering:
Panel
after all) than a drawing tool (like html canvas). – Ruddle