source/SkiaSharp.Views.Uno/SkiaSharp.Views.Uno.WinUI.Shared/SKXamlCanvas.cs (126 lines of code) (raw):
using System;
using Windows.ApplicationModel;
using Windows.Graphics.Display;
using Windows.UI.Core;
#if WINUI
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
#else
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Data;
#endif
#if WINDOWS || WINUI
namespace SkiaSharp.Views.Windows
#else
namespace SkiaSharp.Views.UWP
#endif
{
public partial class SKXamlCanvas : Canvas
{
private const float DpiBase = 96.0f;
private static readonly DependencyProperty ProxyVisibilityProperty =
DependencyProperty.Register(
"ProxyVisibility",
typeof(Visibility),
typeof(SKXamlCanvas),
new PropertyMetadata(Visibility.Visible, OnVisibilityChanged));
private static bool designMode = DesignMode.DesignModeEnabled;
private bool ignorePixelScaling;
private bool isVisible = true;
// workaround for https://github.com/mono/SkiaSharp/issues/1118
private int loadUnloadCounter = 0;
private void Initialize()
{
if (designMode)
return;
var display = DisplayInformation.GetForCurrentView();
OnDpiChanged(display);
Loaded += OnLoaded;
Unloaded += OnUnloaded;
SizeChanged += OnSizeChanged;
var binding = new Binding
{
Path = new PropertyPath(nameof(Visibility)),
Source = this
};
SetBinding(ProxyVisibilityProperty, binding);
}
public SKSize CanvasSize { get; private set; }
public bool IgnorePixelScaling
{
get => ignorePixelScaling;
set
{
ignorePixelScaling = value;
Invalidate();
}
}
public double Dpi { get; private set; } = 1;
public event EventHandler<SKPaintSurfaceEventArgs> PaintSurface;
protected virtual void OnPaintSurface(SKPaintSurfaceEventArgs e)
{
PaintSurface?.Invoke(this, e);
}
private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is SKXamlCanvas canvas && e.NewValue is Visibility visibility)
{
canvas.isVisible = visibility == Visibility.Visible;
canvas.Invalidate();
}
}
private void OnDpiChanged(DisplayInformation sender, object args = null)
{
Dpi = sender.LogicalDpi / DpiBase;
Invalidate();
}
private void OnSizeChanged(object sender, SizeChangedEventArgs e)
{
Invalidate();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
loadUnloadCounter++;
if (loadUnloadCounter != 1)
return;
DoLoaded();
var display = DisplayInformation.GetForCurrentView();
display.DpiChanged += OnDpiChanged;
OnDpiChanged(display);
}
private void OnUnloaded(object sender, RoutedEventArgs e)
{
loadUnloadCounter--;
if (loadUnloadCounter != 0)
return;
DoUnloaded();
var display = DisplayInformation.GetForCurrentView();
display.DpiChanged -= OnDpiChanged;
}
public new void Invalidate()
{
if (Dispatcher.HasThreadAccess)
DoInvalidate();
else
_ = Dispatcher.RunAsync(CoreDispatcherPriority.Normal, DoInvalidate);
}
partial void DoLoaded();
partial void DoUnloaded();
private SKSizeI CreateSize(out SKSizeI unscaledSize, out float dpi)
{
unscaledSize = SKSizeI.Empty;
dpi = (float)Dpi;
var w = ActualWidth;
var h = ActualHeight;
if (!IsPositive(w) || !IsPositive(h))
return SKSizeI.Empty;
unscaledSize = new SKSizeI((int)w, (int)h);
return new SKSizeI((int)(w * dpi), (int)(h * dpi));
static bool IsPositive(double value)
{
return !double.IsNaN(value) && !double.IsInfinity(value) && value > 0;
}
}
}
}