Primary WinForms APIs:
OnPaint(PaintEventArgs)Graphics drawing callsDoubleBufferedPrimary Avalonia APIs:
Control.Render(DrawingContext context)DrawingContext primitives (DrawRectangle, DrawLine, DrawText)| WinForms | Avalonia |
|---|---|
OnPaint override |
Render(DrawingContext) override |
Graphics |
DrawingContext |
Invalidate() |
InvalidateVisual() |
| owner-draw list item handlers | data templates + styles, custom render only if needed |
WinForms C#:
public sealed class MeterControl : Control
{
public int Value { get; set; }
protected override void OnPaint(PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.Clear(Color.Black);
e.Graphics.FillRectangle(Brushes.LimeGreen, 4, 4, Value * 2, Height - 8);
e.Graphics.DrawRectangle(Pens.Gray, 4, 4, Width - 8, Height - 8);
}
}
Avalonia XAML:
<local:MeterControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp.Controls"
Value="64"
Width="220"
Height="24" />
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Media;
public sealed class MeterControl : Control
{
static MeterControl()
{
AffectsRender<MeterControl>(ValueProperty);
}
public static readonly StyledProperty<int> ValueProperty =
AvaloniaProperty.Register<MeterControl, int>(nameof(Value), 0);
public int Value
{
get => GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
public override void Render(DrawingContext context)
{
base.Render(context);
var bounds = Bounds;
var inner = new Rect(4, 4, Math.Max(0, bounds.Width - 8), Math.Max(0, bounds.Height - 8));
var fillWidth = Math.Clamp(Value, 0, 100) / 100.0 * inner.Width;
context.FillRectangle(Brushes.Black, bounds);
context.FillRectangle(Brushes.LimeGreen, new Rect(inner.X, inner.Y, fillWidth, inner.Height));
context.DrawRectangle(null, new Pen(Brushes.Gray, 1), inner);
}
}
AffectsRender<T>(...) (or call InvalidateVisual() from a change handler).