Primary APIs:
TopLevel.GetTopLevel(...)TopLevel.ScreensScreensScreenImportant members:
Screens.ScreenCountScreens.All, Screens.PrimaryScreens.ScreenFromBounds(...)Screens.ScreenFromPoint(...)Screens.ScreenFromTopLevel(...)Screens.ScreenFromVisual(...)Screens.RequestScreenDetails()Screens.Changed eventScreen.Bounds, WorkingArea, Scaling, DisplayName, IsPrimary, CurrentOrientationReference source files:
src/Avalonia.Controls/TopLevel.cssrc/Avalonia.Controls/Screens.cssrc/Avalonia.Controls/Platform/Screen.csUse TopLevel.Screens as read model for connected displays.
Model notes:
All is platform-provided and can change over runtime.WorkingArea may differ from Bounds due to taskbars/notches.Scaling is per-display and relevant for pixel calculations.using Avalonia;
using Avalonia.Controls;
using Avalonia.Platform;
public static class ScreenWorkflows
{
public static Screen? GetCurrentScreen(Control anchor)
{
TopLevel? top = TopLevel.GetTopLevel(anchor);
return top?.Screens?.ScreenFromVisual(anchor);
}
public static PixelRect? GetPrimaryWorkingArea(Control anchor)
{
TopLevel? top = TopLevel.GetTopLevel(anchor);
return top?.Screens?.Primary?.WorkingArea;
}
}
using System;
using Avalonia.Controls;
public sealed class ScreenChangeTracker : IDisposable
{
private readonly Screens? _screens;
private readonly EventHandler _handler;
public ScreenChangeTracker(TopLevel topLevel, Action onChanged)
{
_handler = (_, _) => onChanged();
_screens = topLevel.Screens;
if (_screens is not null)
_screens.Changed += _handler;
}
public void Dispose()
{
if (_screens is not null)
_screens.Changed -= _handler;
}
}
Default mode:
XAML-first complete example:
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:MyApp.ViewModels"
x:DataType="vm:DisplayViewModel">
<StackPanel Margin="12" Spacing="8">
<Button Content="Refresh Displays" Command="{CompiledBinding RefreshScreensCommand}" />
<TextBlock Text="{CompiledBinding PrimaryDisplayName}" />
<TextBlock Text="{CompiledBinding PrimaryWorkingAreaText}" />
</StackPanel>
</UserControl>
Code-only alternative (on request):
using Avalonia.Controls;
public static class CodeOnlyScreenSample
{
public static string DescribePrimary(Control anchor)
{
TopLevel? top = TopLevel.GetTopLevel(anchor);
Screen? primary = top?.Screens?.Primary;
if (primary is null)
return "No screen information available.";
return $"{primary.DisplayName} {primary.WorkingArea} scale={primary.Scaling:0.##}";
}
}
Screens.Changed for dynamic environments.WorkingArea for window placement, not raw Bounds.TopLevel.Bounds where WorkingArea should be used.RequestScreenDetails() and permission.