-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Avalonia 11 Porting Guide
- Update the Avalonia packages to 11.x
- Themes are no longer included in the Avalonia.Desktop package, so you will need to add a package reference to either
Avalonia.Themes.FluentAvalonia.Themes.Simple
- Remove the package reference to
XamlNameReferenceGenerator- Avalonia now includes an inbuilt generator by default - If necessary, update the
<LangVersion>to at least 9 in order to be able to use init-only properties
Avalonia no longer has a dependency on System.Reactive. If you're using reactive features, add a package reference to System.Reactive to your project.
If you don't need the whole of System.Reactive but just want to make a simple subscription to an IObservable<T> you can use the utility class AnonymousObserver<T> provided by Avalonia, for example:
observable.Subscribe(new AnonymousObserver<string>(() => { /* Code to execute when the observable changes. */ }));See #9749, #10105 for more information.
Many interfaces have been removed in Avalonia 11. You should be able to do a global find/replace to replace each of the follow interfaces with its concrete type:
-
IAvaloniaObject->AvaloniaObject -
IBitmap->Bitmap -
IContentPresenter->ContentPresenter -
IControl->Control -
IInteractive->Interactive -
IItemsPresenter->ItemsPresenter -
ILayoutable->Layoutable -
IPanel->Panel -
IStyledElement->StyledElement -
ITemplatedControl->TemplatedControl -
IVisual->Visual
If you have your own interfaces that derive from one of these interfaces you'll need to remove the interface base, and do a cast to the concrete class at the point of usage.
See #9553, #11495 for more information.
The IStyleable interface is now deprecated. In Avalonia 0.10.x, to override a control's style key you implemented IStyleable and added an explicit interface implementation for StyleKey:
class MyButton : Button, IStyleable
{
Type IStyleable.StyleKey => typeof(Button);
}In Avalonia 11, the IStyleable reference will give a deprecated warning. The following should be used instead:
class MyButton : Button
{
protected override Type StyleKeyOverride => typeof(Button);
}See #11380 for more information.
Views that are in the form of a .axaml/.axaml.cs (or .xaml/.xaml.cs) pair now have auto-generated code. To facilitate this:
- Make the class in the .cs file
partial - Remove the
private void InitializeComponent()method - Do NOT remove the call to
InitializeComponent()in the constructor: this method is now a generated method and still needs to be called - Remove the
this.AttachDevTools()call from the constructor -InitializeComponentnow has a parameter which controls whether DevTools is attached in debug mode whose default istrue
Previously, to find a named control declared in the XAML file, a call to this.FindControl<T>(string name) or this.GetControl<T>(string name) was needed. This is now unnecessary - controls in the XAML file with a Name or x:Name attribute will automatically cause a field to be generated in the class to access the named control (as in WPF/UWP etc).
ItemsControl and derived classes such as ListBox and ComboBox now have both an Items property and an ItemsSource as in WPF/UWP.
Items is a readonly collection property that is pre-populated, and ItemsSource is the read/write version that has a default value of null.
Replace any bindings to Items with a binding to ItemsSource:
<ListBox Items="{Binding Items}">
Becomes
<ListBox ItemsSource="{Binding Items}">
In addition:
-
ListBox.VirtualizationModehas been removed, the virtualization mode is changed by changing theItemsPanel:- To disable virtualization use a
StackPanel. - To enable virtualization use a
VirtualizingStackPanel.
- To disable virtualization use a
-
Carousel.IsVirtualizinghas been removed, there is now only a "virtualizing" mode forCarousel - Item container lookup was moved to
ItemsControlas in UWP (old methods are left on ItemContainerGenerator marked with [Obsolete]):ItemsControl.ContainerFromIndex(object item)ItemsControl.IndexFromContainer(Control container)
- The
ItemsandItemTemplateproperties onItemsPresenterhave been removed. The template bindings to these properties in control templates can simply be removed
See #10590, #10827 for more information.
StyledElement.Classes is now a readonly property. When used in an object initializer, code which did the following:
var c = new Control
{
Classes = new Classes("foo", "bar"),
};Should be changed to:
var c = new Control
{
Classes = { "foo", "bar" },
};To manipulate a Classes collection outside of an object initializer use the standard IList<string> methods.
See #11013 for more information.
The TopLEvel.PlatformImpl API is no longer available for controls such as Window. The relevant methods have been moved to TopLevel, WindowBase or Window itself:
-
window.PlatformImpl.Handlebecomeswindow.TryGetHandle() -
window.PlatformImpl.BeginMove(e)becomeswindow.BeginMove()
The IAssetLoader interface is no longer available. Use the static AssetLoader class:
var assets = AvaloniaLocator.Current.GetService<IAssetLoader>();
var bitmap = new Bitmap(assets.Open(new Uri(uri)));Becomes:
var bitmap = new Bitmap(AssetLoader.Open(new Uri(uri)));The virtual AvaloniaObject.OnPropertyChanged method is now non-generic. Replace
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)with
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)Also the technique for getting the old and new values from AvaloniaPropertyChangedEventArgs without boxing has changed:
- Replace
change.NewValue.GetValueOrDefault<T>()withchange.GetNewValue<bool>() - Replace
change.OldValue.GetValueOrDefault<T>()withchange.GetOldValue<bool>() - You can also use
change.GetOldAndNewValue<T>()to get both
See #7980 for more information.
The following events have been renamed:
-
PointerEnter->PointerEntered -
PointerLeave->PointerExited -
ContextMenu-
ContextMenuClosing->Closing -
ContextMenuOpening->Opening
-
-
MenuBase-
MenuClosed->Closed -
MenuOpened->Opened
-
RoutedEventArgs.Source has changed from type IInteractive to type object: cast to a concrete type such as Control to use it.
Previously a full layout pass was achieved by getting the layout root and calling a method on the layout manager:
((ILayoutRoot)control).LayoutManager.ExecuteLayout();The LayoutManager is no longer exposed from the ILayoutRoot, instead call the UpdateLayout method on any control as in WPF/UWP:
control.UpdateLayout();ILayoutable was used in 0.10.x to get the previous measure constraints and arrange bounds. Because ILayoutable is no longer available, these are now exposed from LayoutInformation:
Size? LayoutInformation.GetPreviousMeasureConstraint(Layoutable control)Rect? LayoutInformation.GetPreviousArrangeBounds(Layoutable control)
The focus manager is no longer available via FocusManager.Instance and has instead been move to the TopLevel:
var focusManager = FocusManager.Instance;Becomes:
var focusManager = TopLevel.GetTopLevel(control).FocusManager;In addition the IFocusManager API has been changed.
- To get the currently focused element, use
IFocusManager.GetFocusedEleemnt() - To focus a control use
control.Focus()
There is currently no event for listening to focus changes on IFocusManager. To listen for focus changes, add a listener to the InputElement.GotFocusEvent:
InputElement.GotFocusEvent.Raised.Subscribe(new AnonymousObserver<(object, RoutedEventArgs)>(x => { }));See #11407 for more information.
IVisual was used in 0.10.x to expose the visual parent and visual children of a control. Because IVisual is no longer available, these are now exposed as extension methods in the Avalonia.VisualTree namespace:
using Avalonia.VisualTree;
var visualParent = control.GetVisualParent();
var visualChildren = control.GetVisualChildren();
The Render method on certain controls is now sealed. This is because it is planned to make these controls use composition primitives instead of rendering via DrawingContext.
If you have a control whose Render method was being overloaded but it's now sealed, consider using a base class, for example instead of Border use Decorator. Note that you will now be responsible for drawing the background/border.
See #10299 for more information.
The AvaloniaLocator is no longer available. Most services which were available via the locator now have alternative methods of access such as AssetLocator or TopLevel.FocusManager.
Some applications were using the AvaloniaLocator as a general-purpose service locator. This was never an intended usage of AvaloniaLocator and those application should move to a service locator or DI container designed for the purpose, e.g. Splat or Microsoft.Extensions.DependencyInjection.
-
IRenderer/DeferredRenderer/ImmediateRendererhave now been removed. For performance reasons it is no longer possible to supply your own renderer, everything uses the new composition renderer. -
Renderer.Diagnosticsis nowRendererDiagnostics -
ICustomDrawOperation.Rendernow takes anImmediateDrawingContextinstead of aDrawingContext - Add
.GetTask()to the end of calls toDispatcher.UIThread.InvokeAsyncif directly returning the value in a method which returns aTask -
IRenderRoot.RenderScalinghas been moved toTopLevel.RenderScaling -
LightweightObservableBaseandSingleSubscriberObservableBasehave been made internal. These were utility classes designed for a specific purpose in Avalonia and were not intended to be used by clients as they do not handle certain edge cases. Use the mechanisms provided bySystem.Reactiveto create observables, such asObservable.Create