Browse Source

Merge branch 'master' into refactor/standardassetloader-public

pull/11204/head
Benedikt Stebner 3 years ago
committed by GitHub
parent
commit
7701c8e09c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 32
      build/ExternalConsumers.props
  2. 6
      native/Avalonia.Native/src/OSX/AvnView.mm
  3. 2
      native/Avalonia.Native/src/OSX/AvnWindow.mm
  4. 63
      readme.md
  5. 1
      src/Avalonia.Base/Avalonia.Base.csproj
  6. 3
      src/Avalonia.Base/Data/BindingPriority.cs
  7. 3
      src/Avalonia.Base/Data/InstancedBinding.cs
  8. 3
      src/Avalonia.Base/Input/DataFormats.cs
  9. 3
      src/Avalonia.Base/Input/DataObjectExtensions.cs
  10. 3
      src/Avalonia.Base/Media/Color.cs
  11. 7
      src/Avalonia.Base/Media/DrawingContext.cs
  12. 4
      src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs
  13. 33
      src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs
  14. 42
      src/Avalonia.Base/Threading/Dispatcher.Invoke.cs
  15. 57
      src/Avalonia.Base/Threading/DispatcherFrame.cs
  16. 3
      src/Avalonia.Base/Threading/DispatcherPriority.cs
  17. 5
      src/Avalonia.Base/VisualTree/IVisualWithRoundRectClip.cs
  18. 4
      src/Avalonia.Controls/ContextMenu.cs
  19. 5
      src/Avalonia.Controls/Generators/ItemContainerGenerator.cs
  20. 7
      src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs
  21. 3
      src/Avalonia.Controls/ItemsControl.cs
  22. 3
      src/Avalonia.Controls/Platform/Dialogs/ISystemDialogImpl.cs
  23. 3
      src/Avalonia.Controls/Platform/Dialogs/SystemDialogImpl.cs
  24. 6
      src/Avalonia.Controls/Platform/ManagedDispatcherImpl.cs
  25. 5
      src/Avalonia.Controls/Platform/Screen.cs
  26. 4
      src/Avalonia.Controls/Primitives/Popup.cs
  27. 19
      src/Avalonia.Controls/Primitives/ToggleButton.cs
  28. 3
      src/Avalonia.Controls/Screens.cs
  29. 15
      src/Avalonia.Controls/SystemDialog.cs
  30. 26
      src/Avalonia.Controls/TextBlock.cs
  31. 3
      src/Avalonia.Controls/TreeView.cs
  32. 5
      src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs
  33. 12
      src/Avalonia.Native/WindowImplBase.cs
  34. 7
      src/Avalonia.Native/avn.idl
  35. 4
      src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs
  36. 2
      src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts
  37. 7
      src/Directory.Build.props
  38. 1
      src/Windows/Avalonia.Win32/Avalonia.Win32.csproj
  39. 44
      tests/Avalonia.Base.UnitTests/DispatcherTests.cs
  40. 27
      tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

32
build/ExternalConsumers.props

@ -0,0 +1,32 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<InternalsVisibleTo Include="AvaloniaUI.Xpf.WinApiShim, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a7f4b8b7db0bfb8d74992dc94ecafae031019197ff4263d87ac0a5835fab101c973ccab6fa6e7d90e8f987374f7c6de18dd0b5cd7d6c41e574a8bc66b64836b7c7e707e1aa393d27e33a08f372c1c9965be81658937c85698f4a1c0f73be68a61ffce06d49d1366bf18464c20a29859ccf105fc2d5e35c7ae68919eab668bf8e" />
<InternalsVisibleTo Include="System.Windows.Forms, PublicKey=00000000000000000400000000000000" />
<InternalsVisibleTo Include="System.Windows.Forms.Primitives, PublicKey=00000000000000000400000000000000" />
<InternalsVisibleTo Include="PresentationFramework-SystemData, PublicKey=00000000000000000400000000000000" />
<InternalsVisibleTo Include="PresentationFramework.Aero, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="System.Xaml, PublicKey=00000000000000000400000000000000" />
<InternalsVisibleTo Include="PresentationFramework, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="PresentationFramework-SystemDrawing, PublicKey=00000000000000000400000000000000" />
<InternalsVisibleTo Include="PresentationFramework-SystemCore, PublicKey=00000000000000000400000000000000" />
<InternalsVisibleTo Include="WindowsFormsIntegration, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="PresentationFramework.AeroLite, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="PresentationFramework.Aero2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="UIAutomationClient, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="PresentationFramework.Luna, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="UIAutomationTypes, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="PresentationFramework.Royale, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="System.Windows.Input.Manipulations, PublicKey=00000000000000000400000000000000" />
<InternalsVisibleTo Include="System.Windows.Controls.Ribbon, PublicKey=00000000000000000400000000000000" />
<InternalsVisibleTo Include="PresentationFramework-SystemXml, PublicKey=00000000000000000400000000000000" />
<InternalsVisibleTo Include="ReachFramework, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="System.Printing, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="PresentationFramework-SystemXmlLinq, PublicKey=00000000000000000400000000000000" />
<InternalsVisibleTo Include="PresentationUI, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="Atlantis, PublicKey=0024000004800000940000000602000000240000525341310004000001000100a7f4b8b7db0bfb8d74992dc94ecafae031019197ff4263d87ac0a5835fab101c973ccab6fa6e7d90e8f987374f7c6de18dd0b5cd7d6c41e574a8bc66b64836b7c7e707e1aa393d27e33a08f372c1c9965be81658937c85698f4a1c0f73be68a61ffce06d49d1366bf18464c20a29859ccf105fc2d5e35c7ae68919eab668bf8e" />
<InternalsVisibleTo Include="WindowsBase, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="PresentationFramework.Classic, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="UIAutomationProvider, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
<InternalsVisibleTo Include="PresentationCore, PublicKey=0024000004800000940000000602000000240000525341310004000001000100b5fc90e7027f67871e773a8fde8938c81dd402ba65b9201d60593e96c492651e889cc13f1415ebb53fac1131ae0bd333c5ee6021672d9718ea31a8aebd0da0072f25d87dba6fc90ffd598ed4da35e44c398c454307e8e33b8426143daec9f596836f97c8f74750e5975c64e2189f45def46b2a2b1247adc3652bf5c308055da9" />
</ItemGroup>
</Project>

6
native/Avalonia.Native/src/OSX/AvnView.mm

@ -275,7 +275,7 @@
delta.Y = [event deltaY]; delta.Y = [event deltaY];
} }
uint32 timestamp = static_cast<uint32>([event timestamp] * 1000); uint64_t timestamp = static_cast<uint64_t>([event timestamp] * 1000);
auto modifiers = [self getModifiers:[event modifierFlags]]; auto modifiers = [self getModifiers:[event modifierFlags]];
if(type != Move || if(type != Move ||
@ -444,7 +444,7 @@
auto key = s_KeyMap[[event keyCode]]; auto key = s_KeyMap[[event keyCode]];
uint32_t timestamp = static_cast<uint32_t>([event timestamp] * 1000); uint64_t timestamp = static_cast<uint64_t>([event timestamp] * 1000);
auto modifiers = [self getModifiers:[event modifierFlags]]; auto modifiers = [self getModifiers:[event modifierFlags]];
if(_parent != nullptr) if(_parent != nullptr)
@ -657,7 +657,7 @@
[self unmarkText]; [self unmarkText];
uint32_t timestamp = static_cast<uint32_t>([NSDate timeIntervalSinceReferenceDate] * 1000); uint64_t timestamp = static_cast<uint64_t>([NSDate timeIntervalSinceReferenceDate] * 1000);
_lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(timestamp, [text UTF8String]); _lastKeyHandled = _parent->BaseEvents->RawTextInputEvent(timestamp, [text UTF8String]);

2
native/Avalonia.Native/src/OSX/AvnWindow.mm

@ -460,7 +460,7 @@
auto point = [self translateLocalPoint:avnPoint]; auto point = [self translateLocalPoint:avnPoint];
AvnVector delta = { 0, 0 }; AvnVector delta = { 0, 0 };
_parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast<uint32>([event timestamp] * 1000), AvnInputModifiersNone, point, delta); _parent->BaseEvents->RawMouseEvent(NonClientLeftButtonDown, static_cast<uint64>([event timestamp] * 1000), AvnInputModifiersNone, point, delta);
} }
if(!_isTransitioningToFullScreen) if(!_isTransitioningToFullScreen)

63
readme.md

@ -1,26 +1,43 @@
[![GH_Banner](https://user-images.githubusercontent.com/552074/218457976-92e76834-9e22-4e35-acfa-aa50281bc0f9.png)](https://avaloniaui.net/xpf) ![Star our repo to show support](https://user-images.githubusercontent.com/552074/235945895-1b896994-a0b6-4e7c-a522-c5688c4ec1b9.png)
![Header](https://user-images.githubusercontent.com/552074/235865745-2a8e7274-4f66-4f77-8f05-feeb76e7d478.png)
[![Telegram](https://raw.githubusercontent.com/Patrolavia/telegram-badge/master/chat.svg)](https://t.me/Avalonia) [![Telegram](https://raw.githubusercontent.com/Patrolavia/telegram-badge/master/chat.svg)](https://t.me/Avalonia)
[![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) [![Discord](https://img.shields.io/badge/discord-join%20chat-46BC99)]( https://aka.ms/dotnet-discord) [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) ![License](https://img.shields.io/github/license/avaloniaui/avalonia.svg) [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/AvaloniaUI/Avalonia?utm_campaign=pr-badge&utm_content=badge&utm_medium=badge&utm_source=badge) [![Discord](https://img.shields.io/badge/discord-join%20chat-46BC99)]( https://aka.ms/dotnet-discord) [![Build Status](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_apis/build/status/AvaloniaUI.Avalonia)](https://dev.azure.com/AvaloniaUI/AvaloniaUI/_build/latest?definitionId=4) [![Backers on Open Collective](https://opencollective.com/Avalonia/backers/badge.svg)](#backers) [![Sponsors on Open Collective](https://opencollective.com/Avalonia/sponsors/badge.svg)](#sponsors) ![License](https://img.shields.io/github/license/avaloniaui/avalonia.svg)
<br /> <br />
[![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) [![downloads](https://img.shields.io/nuget/dt/avalonia)](https://www.nuget.org/packages/Avalonia) ![Size](https://img.shields.io/github/repo-size/avaloniaui/avalonia.svg) [![NuGet](https://img.shields.io/nuget/v/Avalonia.svg)](https://www.nuget.org/packages/Avalonia) [![downloads](https://img.shields.io/nuget/dt/avalonia)](https://www.nuget.org/packages/Avalonia) ![Size](https://img.shields.io/github/repo-size/avaloniaui/avalonia.svg)
# ⚠️ **v11 Update - Pausing community contributions** ⚠️ **v11 Update - [Pausing community contributions](https://github.com/AvaloniaUI/Avalonia/discussions/10599)**
for more information see [this](https://github.com/AvaloniaUI/Avalonia/discussions/10599) discussion.
## 📖 About ## 📖 About
Avalonia is a cross-platform UI framework for dotnet, providing a flexible styling system and supporting a wide range of Operating Systems such as Windows, Linux, macOS. Avalonia is mature and production ready. We also have in beta release support for iOS, Android and in early stages support for browser via WASM. [Avalonia](https://avaloniaui.net) is a cross-platform UI framework for dotnet, providing a flexible styling system and supporting a wide range of platforms such as Windows, macOS, Linux, iOS, Android and WebAssembly. Avalonia is mature and production ready and is used by companies, including [Schneider Electric](https://avaloniaui.net/showcase#se), [Unity](https://avaloniaui.net/showcase#unity), [JetBrains](https://avaloniaui.net/showcase#rider) and [Github](https://avaloniaui.net/showcase#github).
Considered by many to be the spiritual successor to WPF, Avalonia UI provides a familiar, modern development experience for XAML developers creating cross-platform applications. While Avalonia UI is [similar to WPF](https://docs.avaloniaui.net/misc/wpf), it isn't a 1:1 copy, and you'll find plenty of improvements.
![image](https://user-images.githubusercontent.com/4672627/152126443-932966cf-57e7-4e77-9be6-62463a66b9f8.png) For those seeking a cross-platform WPF, we have created [Avalonia XPF](https://avaloniaui.net/xpf), enabling WPF applications to run on macOS and Linux with little to no code changes. Avalonia XPF is a commercial product and is licensed per-app, per-platform.
To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239). You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been. [Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia! #### Roadmap
To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239).
#### Breaking Changes
You can also see what [breaking changes](https://github.com/AvaloniaUI/Avalonia/issues/3538) we have planned and what our [past breaking changes](https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes) have been.
#### Awesome Avalonia
[Awesome Avalonia](https://github.com/AvaloniaCommunity/awesome-avalonia) is community-curated list of awesome Avalonia UI tools, libraries, projects and resources. Go and see what people are building with Avalonia!
## 🚀 Getting Started ## 🚀 Getting Started
See our [Get Started](https://avaloniaui.net/GettingStarted) guide to begin developing apps with Avalonia UI.
### Visual Studio
The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](https://docs.avaloniaui.net/docs/getting-started). The Avalonia [Visual Studio Extension](https://marketplace.visualstudio.com/items?itemName=AvaloniaTeam.AvaloniaforVisualStudio) contains project and control templates that will help you get started, or you can use the .NET Core CLI. For a starter guide see our [documentation](https://docs.avaloniaui.net/docs/getting-started).
### JetBrains Rider
[JetBrains Rider](https://www.jetbrains.com/rider/whatsnew/?mkt_tok=eyJpIjoiTURBNU1HSmhNV0kwTUdFMiIsInQiOiJtNnU2VEc1TlNLa1ZRVkROYmdZYVpYREJsaU1qdUhmS3dxSzRHczdYWHl0RVlTNDMwSFwvNUs3VENTNVM0bVcyNFdaRmVYZzVWTTF1N3VrQWNGTkJreEhlam1hMlB4UVVWcHBGM1dNOUxoXC95YnRQdGgyUXl1YmZCM3h3d3BVWWdBIn0%3D#avalonia-support) now has official support for Avalonia.
Code completion, inspections and refactorings are supported out of the box, for XAML previewer add `https://plugins.jetbrains.com/plugins/dev/14839` to plugin repositories and install [AvaloniaRider](https://github.com/ForNeVeR/AvaloniaRider) plugin.
### Avalonia Packages
Avalonia is delivered via <b>NuGet</b> package manager. You can find the packages here: https://www.nuget.org/packages/Avalonia/ Avalonia is delivered via <b>NuGet</b> package manager. You can find the packages here: https://www.nuget.org/packages/Avalonia/
Use these commands in the Package Manager console to install Avalonia manually: Use these commands in the Package Manager console to install Avalonia manually:
@ -30,31 +47,26 @@ Install-Package Avalonia.Desktop
``` ```
## Showcase ## Showcase
[![Showcase_Banner](https://user-images.githubusercontent.com/552074/235946124-bf6fda52-0c9f-4730-868b-0de957e5b97b.png)](https://avaloniaui.net/showcase)
Examples of UIs built with Avalonia
<video src="https://user-images.githubusercontent.com/4672627/152325602-28df36ec-6444-44a6-aebe-90ad52c8f27a.mp4"></video>
([Lunacy](https://icons8.com/lunacy))
![image](https://user-images.githubusercontent.com/4672627/152325740-261c27a3-e6f0-4662-bff7-4796d4940e04.png)
([PlasticSCM](https://www.plasticscm.com/))
![image](https://user-images.githubusercontent.com/4672627/152326453-14944c4d-33da-4d50-a268-b87f80927adb.png)
([WasabiWallet](https://www.wasabiwallet.io/))
See what others have built with Avalonia UI on our [Showcase](https://avaloniaui.net/Showcase). We welcome submissions!
## JetBrains Rider
[JetBrains Rider](https://www.jetbrains.com/rider/whatsnew/?mkt_tok=eyJpIjoiTURBNU1HSmhNV0kwTUdFMiIsInQiOiJtNnU2VEc1TlNLa1ZRVkROYmdZYVpYREJsaU1qdUhmS3dxSzRHczdYWHl0RVlTNDMwSFwvNUs3VENTNVM0bVcyNFdaRmVYZzVWTTF1N3VrQWNGTkJreEhlam1hMlB4UVVWcHBGM1dNOUxoXC95YnRQdGgyUXl1YmZCM3h3d3BVWWdBIn0%3D#avalonia-support) now has official support for Avalonia.
Code completion, inspections and refactorings are supported out of the box, for XAML previewer add `https://plugins.jetbrains.com/plugins/dev/14839` to plugin repositories and install [AvaloniaRider](https://github.com/ForNeVeR/AvaloniaRider) plugin.
## Bleeding Edge Builds ## Bleeding Edge Builds
We also have a [nightly build](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed) which tracks the current state of master. Although these packages are less stable than the release on NuGet.org, you'll get all the latest features and bugfixes right away and many of our users actually prefer this feed! We also have a [nightly build](https://github.com/AvaloniaUI/Avalonia/wiki/Using-nightly-build-feed) which tracks the current state of master. Although these packages are less stable than the release on NuGet.org, you'll get all the latest features and bugfixes right away and many of our users actually prefer this feed!
## Documentation ## Learning
Documentation can be found at https://docs.avaloniaui.net. We also have a [tutorial](https://docs.avaloniaui.net/docs/getting-started/programming-with-avalonia) over there for newcomers. ### Documentation
Documentation can be found at https://docs.avaloniaui.net.
### Tutorials
We also have a [tutorial](https://docs.avaloniaui.net/docs/getting-started/programming-with-avalonia) over there for newcomers.
### Samples
We have a [range of samples](https://github.com/AvaloniaUI/Avalonia.Samples) to help you get started.
## Building and Using ## Building and Using
@ -116,3 +128,8 @@ We have a range of [support plans available](https://avaloniaui.net/support) for
## .NET Foundation ## .NET Foundation
This project is supported by the [.NET Foundation](https://dotnetfoundation.org). This project is supported by the [.NET Foundation](https://dotnetfoundation.org).
## Avalonia XPF
Unleash the full potential of your existing WPF apps with our cross-platform UI framework, enabling WPF apps to run on macOS and Linux without requiring expensive and risky rewrites.
[![GH_Banner](https://user-images.githubusercontent.com/552074/218457976-92e76834-9e22-4e35-acfa-aa50281bc0f9.png)](https://avaloniaui.net/xpf)

1
src/Avalonia.Base/Avalonia.Base.csproj

@ -22,6 +22,7 @@
<Import Project="..\..\build\SourceGenerators.props" /> <Import Project="..\..\build\SourceGenerators.props" />
<ItemGroup> <ItemGroup>
<Compile Include="..\Shared\IsExternalInit.cs" Link="IsExternalInit.cs" /> <Compile Include="..\Shared\IsExternalInit.cs" Link="IsExternalInit.cs" />
<Compile Include="..\Shared\ModuleInitializer.cs" Link="ModuleInitializer.cs" />
<Compile Include="..\Shared\StringCompatibilityExtensions.cs" Link="Compatibility\StringCompatibilityExtensions.cs" /> <Compile Include="..\Shared\StringCompatibilityExtensions.cs" Link="Compatibility\StringCompatibilityExtensions.cs" />
</ItemGroup> </ItemGroup>

3
src/Avalonia.Base/Data/BindingPriority.cs

@ -1,4 +1,5 @@
using System; using System;
using System.ComponentModel;
namespace Avalonia.Data namespace Avalonia.Data
{ {
@ -47,7 +48,7 @@ namespace Avalonia.Data
/// </summary> /// </summary>
Unset = int.MaxValue, Unset = int.MaxValue,
[Obsolete("Use Template priority")] [Obsolete("Use Template priority"), EditorBrowsable(EditorBrowsableState.Never)]
TemplatedParent = Template, TemplatedParent = Template,
} }
} }

3
src/Avalonia.Base/Data/InstancedBinding.cs

@ -1,4 +1,5 @@
using System; using System;
using System.ComponentModel;
using Avalonia.Reactive; using Avalonia.Reactive;
using ObservableEx = Avalonia.Reactive.Observable; using ObservableEx = Avalonia.Reactive.Observable;
@ -49,7 +50,7 @@ namespace Avalonia.Data
/// </summary> /// </summary>
public IObservable<object?> Source { get; } public IObservable<object?> Source { get; }
[Obsolete("Use Source property")] [Obsolete("Use Source property"), EditorBrowsable(EditorBrowsableState.Never)]
public IObservable<object?> Observable => Source; public IObservable<object?> Observable => Source;
/// <summary> /// <summary>

3
src/Avalonia.Base/Input/DataFormats.cs

@ -1,4 +1,5 @@
using System; using System;
using System.ComponentModel;
namespace Avalonia.Input namespace Avalonia.Input
{ {
@ -17,7 +18,7 @@ namespace Avalonia.Input
/// <summary> /// <summary>
/// Dataformat for one or more filenames /// Dataformat for one or more filenames
/// </summary> /// </summary>
[Obsolete("Use DataFormats.Files, this format is supported only on desktop platforms.")] [Obsolete("Use DataFormats.Files, this format is supported only on desktop platforms."), EditorBrowsable(EditorBrowsableState.Never)]
public static readonly string FileNames = nameof(FileNames); public static readonly string FileNames = nameof(FileNames);
} }
} }

3
src/Avalonia.Base/Input/DataObjectExtensions.cs

@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
@ -25,7 +26,7 @@ namespace Avalonia.Input
/// <returns> /// <returns>
/// Collection of file names. If format isn't available, returns null. /// Collection of file names. If format isn't available, returns null.
/// </returns> /// </returns>
[System.Obsolete("Use GetFiles, this method is supported only on desktop platforms.")] [System.Obsolete("Use GetFiles, this method is supported only on desktop platforms."), EditorBrowsable(EditorBrowsableState.Never)]
public static IEnumerable<string>? GetFileNames(this IDataObject dataObject) public static IEnumerable<string>? GetFileNames(this IDataObject dataObject)
{ {
return (dataObject.Get(DataFormats.FileNames) as IEnumerable<string>) return (dataObject.Get(DataFormats.FileNames) as IEnumerable<string>)

3
src/Avalonia.Base/Media/Color.cs

@ -6,6 +6,7 @@
// Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation. // Licensed to The Avalonia Project under MIT License, courtesy of The .NET Foundation.
using System; using System;
using System.ComponentModel;
using System.Globalization; using System.Globalization;
#if !BUILDTASK #if !BUILDTASK
using Avalonia.Animation.Animators; using Avalonia.Animation.Animators;
@ -465,7 +466,7 @@ namespace Avalonia.Media
} }
/// <inheritdoc cref="Color.ToUInt32"/> /// <inheritdoc cref="Color.ToUInt32"/>
[Obsolete("Use Color.ToUInt32() instead.")] [Obsolete("Use Color.ToUInt32() instead."), EditorBrowsable(EditorBrowsableState.Never)]
public uint ToUint32() public uint ToUint32()
{ {
return ToUInt32(); return ToUInt32();

7
src/Avalonia.Base/Media/DrawingContext.cs

@ -5,6 +5,7 @@ using Avalonia.Rendering.SceneGraph;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.Utilities; using Avalonia.Utilities;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using System.ComponentModel;
namespace Avalonia.Media namespace Avalonia.Media
{ {
@ -417,11 +418,11 @@ namespace Avalonia.Media
return new PushedState(this); return new PushedState(this);
} }
[Obsolete("Use PushTransform")] [Obsolete("Use PushTransform"), EditorBrowsable(EditorBrowsableState.Never)]
public PushedState PushPreTransform(Matrix matrix) => PushTransform(matrix); public PushedState PushPreTransform(Matrix matrix) => PushTransform(matrix);
[Obsolete("Use PushTransform")] [Obsolete("Use PushTransform"), EditorBrowsable(EditorBrowsableState.Never)]
public PushedState PushPostTransform(Matrix matrix) => PushTransform(matrix); public PushedState PushPostTransform(Matrix matrix) => PushTransform(matrix);
[Obsolete("Use PushTransform")] [Obsolete("Use PushTransform"), EditorBrowsable(EditorBrowsableState.Never)]
public PushedState PushTransformContainer() => PushTransform(Matrix.Identity); public PushedState PushTransformContainer() => PushTransform(Matrix.Identity);

4
src/Avalonia.Base/Media/TextFormatting/TextCharacters.cs

@ -185,7 +185,9 @@ namespace Avalonia.Media.TextFormatting
} }
//Stop at the first missing glyph //Stop at the first missing glyph
if (!currentCodepoint.IsBreakChar && !glyphTypeface.TryGetGlyph(currentCodepoint, out _)) if (!currentCodepoint.IsBreakChar &&
currentCodepoint.GeneralCategory != GeneralCategory.Control &&
!glyphTypeface.TryGetGlyph(currentCodepoint, out _))
{ {
break; break;
} }

33
src/Avalonia.Base/Media/TextFormatting/TextLineImpl.cs

@ -83,7 +83,7 @@ namespace Avalonia.Media.TextFormatting
/// <inheritdoc/> /// <inheritdoc/>
public override void Draw(DrawingContext drawingContext, Point lineOrigin) public override void Draw(DrawingContext drawingContext, Point lineOrigin)
{ {
var (currentX, currentY) = lineOrigin; var (currentX, currentY) = lineOrigin + new Point(Start, 0);
foreach (var textRun in _textRuns) foreach (var textRun in _textRuns)
{ {
@ -698,7 +698,7 @@ namespace Avalonia.Media.TextFormatting
i = lastRunIndex; i = lastRunIndex;
//Possible overlap at runs of different direction //Possible overlap at runs of different direction
if (directionalWidth == 0) if (directionalWidth == 0 && i < _textRuns.Length - 1)
{ {
//In case a run only contains a linebreak we don't want to skip it. //In case a run only contains a linebreak we don't want to skip it.
if (currentRun is ShapedTextRun shaped) if (currentRun is ShapedTextRun shaped)
@ -844,7 +844,7 @@ namespace Avalonia.Media.TextFormatting
i = firstRunIndex; i = firstRunIndex;
//Possible overlap at runs of different direction //Possible overlap at runs of different direction
if (directionalWidth == 0) if (directionalWidth == 0 && i > 0)
{ {
//In case a run only contains a linebreak we don't want to skip it. //In case a run only contains a linebreak we don't want to skip it.
if (currentRun is ShapedTextRun shaped) if (currentRun is ShapedTextRun shaped)
@ -860,8 +860,8 @@ namespace Avalonia.Media.TextFormatting
} }
} }
TextBounds? textBounds = null;
int coveredLength; int coveredLength;
TextBounds? textBounds;
switch (currentDirection) switch (currentDirection)
{ {
@ -942,6 +942,13 @@ namespace Avalonia.Media.TextFormatting
new TextRunBounds( new TextRunBounds(
new Rect(startX, 0, drawableTextRun.Size.Width, Height), currentPosition, currentRun.Length, currentRun)); new Rect(startX, 0, drawableTextRun.Size.Width, Height), currentPosition, currentRun.Length, currentRun));
} }
else
{
//Add potential TextEndOfParagraph
textRunBounds.Add(
new TextRunBounds(
new Rect(endX, 0, 0, Height), currentPosition, currentRun.Length, currentRun));
}
currentPosition += currentRun.Length; currentPosition += currentRun.Length;
@ -1007,6 +1014,13 @@ namespace Avalonia.Media.TextFormatting
endX += drawableTextRun.Size.Width; endX += drawableTextRun.Size.Width;
} }
else
{
//Add potential TextEndOfParagraph
textRunBounds.Add(
new TextRunBounds(
new Rect(endX, 0, 0, Height), currentPosition, currentRun.Length, currentRun));
}
currentPosition += currentRun.Length; currentPosition += currentRun.Length;
@ -1409,8 +1423,6 @@ namespace Avalonia.Media.TextFormatting
var fontMetrics = _paragraphProperties.DefaultTextRunProperties.CachedGlyphTypeface.Metrics; var fontMetrics = _paragraphProperties.DefaultTextRunProperties.CachedGlyphTypeface.Metrics;
var fontRenderingEmSize = _paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize; var fontRenderingEmSize = _paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize;
var scale = fontRenderingEmSize / fontMetrics.DesignEmHeight; var scale = fontRenderingEmSize / fontMetrics.DesignEmHeight;
var width = 0d;
var widthIncludingWhitespace = 0d; var widthIncludingWhitespace = 0d;
var trailingWhitespaceLength = 0; var trailingWhitespaceLength = 0;
var newLineLength = 0; var newLineLength = 0;
@ -1422,13 +1434,6 @@ namespace Avalonia.Media.TextFormatting
var lineHeight = _paragraphProperties.LineHeight; var lineHeight = _paragraphProperties.LineHeight;
var lastRunIndex = _textRuns.Length - 1;
if (lastRunIndex > 0 && _textRuns[lastRunIndex] is TextEndOfLine)
{
lastRunIndex--;
}
for (var index = 0; index < _textRuns.Length; index++) for (var index = 0; index < _textRuns.Length; index++)
{ {
switch (_textRuns[index]) switch (_textRuns[index])
@ -1486,7 +1491,7 @@ namespace Avalonia.Media.TextFormatting
} }
} }
width = widthIncludingWhitespace; var width = widthIncludingWhitespace;
for (var i = _textRuns.Length - 1; i >= 0; i--) for (var i = _textRuns.Length - 1; i >= 0; i--)
{ {

42
src/Avalonia.Base/Threading/Dispatcher.Invoke.cs

@ -248,11 +248,11 @@ public partial class Dispatcher
/// An operation representing the queued delegate to be invoked. /// An operation representing the queued delegate to be invoked.
/// </returns> /// </returns>
/// <remarks> /// <remarks>
/// Note that the default priority is DispatcherPriority.Normal. /// Note that the default priority is DispatcherPriority.Default.
/// </remarks> /// </remarks>
public DispatcherOperation InvokeAsync(Action callback) public DispatcherOperation InvokeAsync(Action callback)
{ {
return InvokeAsync(callback, DispatcherPriority.Normal, CancellationToken.None); return InvokeAsync(callback, default, CancellationToken.None);
} }
/// <summary> /// <summary>
@ -326,11 +326,11 @@ public partial class Dispatcher
/// An operation representing the queued delegate to be invoked. /// An operation representing the queued delegate to be invoked.
/// </returns> /// </returns>
/// <remarks> /// <remarks>
/// Note that the default priority is DispatcherPriority.Normal. /// Note that the default priority is DispatcherPriority.Default.
/// </remarks> /// </remarks>
public DispatcherOperation<TResult> InvokeAsync<TResult>(Func<TResult> callback) public DispatcherOperation<TResult> InvokeAsync<TResult>(Func<TResult> callback)
{ {
return InvokeAsync(callback, DispatcherPriority.Normal, CancellationToken.None); return InvokeAsync(callback, DispatcherPriority.Default, CancellationToken.None);
} }
/// <summary> /// <summary>
@ -541,6 +541,18 @@ public partial class Dispatcher
InvokeAsyncImpl(new DispatcherOperation(this, priority, action, true), CancellationToken.None); InvokeAsyncImpl(new DispatcherOperation(this, priority, action, true), CancellationToken.None);
} }
/// <summary>
/// Executes the specified Func&lt;Task&gt; asynchronously on the
/// thread that the Dispatcher was created on
/// </summary>
/// <param name="callback">
/// A Func&lt;Task&gt; delegate to invoke through the dispatcher.
/// </param>
/// <returns>
/// An task that completes after the task returned from callback finishes.
/// </returns>
public Task InvokeAsync(Func<Task> callback) => InvokeAsync(callback, DispatcherPriority.Default);
/// <summary> /// <summary>
/// Executes the specified Func&lt;Task&gt; asynchronously on the /// Executes the specified Func&lt;Task&gt; asynchronously on the
/// thread that the Dispatcher was created on /// thread that the Dispatcher was created on
@ -556,11 +568,29 @@ public partial class Dispatcher
/// <returns> /// <returns>
/// An task that completes after the task returned from callback finishes /// An task that completes after the task returned from callback finishes
/// </returns> /// </returns>
public Task InvokeAsync(Func<Task> callback, DispatcherPriority priority = default) public Task InvokeAsync(Func<Task> callback, DispatcherPriority priority)
{ {
_ = callback ?? throw new ArgumentNullException(nameof(callback)); _ = callback ?? throw new ArgumentNullException(nameof(callback));
return InvokeAsync<Task>(callback, priority).GetTask().Unwrap(); return InvokeAsync<Task>(callback, priority).GetTask().Unwrap();
} }
/// <summary>
/// Executes the specified Func&lt;Task&lt;TResult&gt;&gt; asynchronously on the
/// thread that the Dispatcher was created on
/// </summary>
/// <param name="action">
/// A Func&lt;Task&lt;TResult&gt;&gt; delegate to invoke through the dispatcher.
/// </param>
/// <param name="priority">
/// The priority that determines in what order the specified
/// callback is invoked relative to the other pending operations
/// in the Dispatcher.
/// </param>
/// <returns>
/// An task that completes after the task returned from callback finishes
/// </returns>
public Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> action) =>
InvokeAsync(action, DispatcherPriority.Default);
/// <summary> /// <summary>
/// Executes the specified Func&lt;Task&lt;TResult&gt;&gt; asynchronously on the /// Executes the specified Func&lt;Task&lt;TResult&gt;&gt; asynchronously on the
@ -577,7 +607,7 @@ public partial class Dispatcher
/// <returns> /// <returns>
/// An task that completes after the task returned from callback finishes /// An task that completes after the task returned from callback finishes
/// </returns> /// </returns>
public Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> action, DispatcherPriority priority = default) public Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> action, DispatcherPriority priority)
{ {
_ = action ?? throw new ArgumentNullException(nameof(action)); _ = action ?? throw new ArgumentNullException(nameof(action));
return InvokeAsync<Task<TResult>>(action, priority).GetTask().Unwrap(); return InvokeAsync<Task<TResult>>(action, priority).GetTask().Unwrap();

57
src/Avalonia.Base/Threading/DispatcherFrame.cs

@ -91,31 +91,44 @@ public class DispatcherFrame
internal void Run(IControlledDispatcherImpl impl) internal void Run(IControlledDispatcherImpl impl)
{ {
// Since the actual platform run loop is controlled by a Cancellation token, we are restarting Dispatcher.VerifyAccess();
// it if frame still needs to run
while (Continue) // Since the actual platform run loop is controlled by a Cancellation token, we have an
RunCore(impl); // outer loop that restarts the platform one in case Continue was set to true after being set to false
} while (true)
private void RunCore(IControlledDispatcherImpl impl)
{
if (_isRunning)
throw new InvalidOperationException("This frame is already running");
_isRunning = true;
try
{
_cancellationTokenSource = new CancellationTokenSource();
// Wake up the dispatcher in case it has pending jobs
Dispatcher.RequestProcessing();
impl.RunLoop(_cancellationTokenSource.Token);
}
finally
{ {
_isRunning = false; // Take the instance lock since `Continue` is changed from one too
_cancellationTokenSource?.Cancel(); lock (Dispatcher.InstanceLock)
_cancellationTokenSource = null; {
if (!Continue)
return;
if (_isRunning)
throw new InvalidOperationException("This frame is already running");
_cancellationTokenSource = new CancellationTokenSource();
_isRunning = true;
}
try
{
// Wake up the dispatcher in case it has pending jobs
Dispatcher.RequestProcessing();
impl.RunLoop(_cancellationTokenSource.Token);
}
finally
{
lock (Dispatcher.InstanceLock)
{
_isRunning = false;
_cancellationTokenSource?.Cancel();
_cancellationTokenSource?.Dispose();
_cancellationTokenSource = null;
}
}
} }
} }
internal void MaybeExitOnDispatcherRequest() internal void MaybeExitOnDispatcherRequest()
{ {

3
src/Avalonia.Base/Threading/DispatcherPriority.cs

@ -1,4 +1,5 @@
using System; using System;
using System.ComponentModel;
namespace Avalonia.Threading namespace Avalonia.Threading
{ {
@ -100,7 +101,7 @@ namespace Avalonia.Threading
/// <summary> /// <summary>
/// The job will be processed with the same priority as data binding. /// The job will be processed with the same priority as data binding.
/// </summary> /// </summary>
[Obsolete("WPF compatibility")] public static readonly DispatcherPriority DataBind = new(Layout); [Obsolete("WPF compatibility"), EditorBrowsable(EditorBrowsableState.Never)] public static readonly DispatcherPriority DataBind = new(Layout);
/// <summary> /// <summary>
/// The job will be processed with normal priority. /// The job will be processed with normal priority.

5
src/Avalonia.Base/VisualTree/IVisualWithRoundRectClip.cs

@ -1,14 +1,15 @@
using System; using System;
using System.ComponentModel;
namespace Avalonia.VisualTree namespace Avalonia.VisualTree
{ {
[Obsolete("Internal API, will be removed in future versions, you've been warned")] [Obsolete("Internal API, will be removed in future versions, you've been warned"), EditorBrowsable(EditorBrowsableState.Never)]
public interface IVisualWithRoundRectClip public interface IVisualWithRoundRectClip
{ {
/// <summary> /// <summary>
/// Gets a value indicating the corner radius of control's clip bounds /// Gets a value indicating the corner radius of control's clip bounds
/// </summary> /// </summary>
[Obsolete("Internal API, will be removed in future versions, you've been warned")] [Obsolete("Internal API, will be removed in future versions, you've been warned"), EditorBrowsable(EditorBrowsableState.Never)]
CornerRadius ClipToBoundsRadius { get; } CornerRadius ClipToBoundsRadius { get; }
} }

4
src/Avalonia.Controls/ContextMenu.cs

@ -64,7 +64,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Defines the <see cref="PlacementMode"/> property. /// Defines the <see cref="PlacementMode"/> property.
/// </summary> /// </summary>
[Obsolete("Use the Placement property instead.")] [Obsolete("Use the Placement property instead."), EditorBrowsable(EditorBrowsableState.Never)]
public static readonly StyledProperty<PlacementMode> PlacementModeProperty = PlacementProperty; public static readonly StyledProperty<PlacementMode> PlacementModeProperty = PlacementProperty;
/// <summary> /// <summary>
@ -157,7 +157,7 @@ namespace Avalonia.Controls
} }
/// <inheritdoc cref="Placement"/> /// <inheritdoc cref="Placement"/>
[Obsolete("Use the Placement property instead.")] [Obsolete("Use the Placement property instead."), EditorBrowsable(EditorBrowsableState.Never)]
public PlacementMode PlacementMode public PlacementMode PlacementMode
{ {
get => GetValue(PlacementProperty); get => GetValue(PlacementProperty);

5
src/Avalonia.Controls/Generators/ItemContainerGenerator.cs

@ -1,4 +1,5 @@
using System; using System;
using System.ComponentModel;
namespace Avalonia.Controls.Generators namespace Avalonia.Controls.Generators
{ {
@ -131,10 +132,10 @@ namespace Avalonia.Controls.Generators
/// </remarks> /// </remarks>
public void ClearItemContainer(Control container) => _owner.ClearItemContainer(container); public void ClearItemContainer(Control container) => _owner.ClearItemContainer(container);
[Obsolete("Use ItemsControl.ContainerFromIndex")] [Obsolete("Use ItemsControl.ContainerFromIndex"), EditorBrowsable(EditorBrowsableState.Never)]
public Control? ContainerFromIndex(int index) => _owner.ContainerFromIndex(index); public Control? ContainerFromIndex(int index) => _owner.ContainerFromIndex(index);
[Obsolete("Use ItemsControl.IndexFromContainer")] [Obsolete("Use ItemsControl.IndexFromContainer"), EditorBrowsable(EditorBrowsableState.Never)]
public int IndexFromContainer(Control container) => _owner.IndexFromContainer(container); public int IndexFromContainer(Control container) => _owner.IndexFromContainer(container);
} }
} }

7
src/Avalonia.Controls/Generators/TreeItemContainerGenerator.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
namespace Avalonia.Controls.Generators namespace Avalonia.Controls.Generators
{ {
@ -20,13 +21,13 @@ namespace Avalonia.Controls.Generators
internal TreeContainerIndex(TreeView owner) => _owner = owner; internal TreeContainerIndex(TreeView owner) => _owner = owner;
[Obsolete("Use TreeView.GetRealizedTreeContainers")] [Obsolete("Use TreeView.GetRealizedTreeContainers"), EditorBrowsable(EditorBrowsableState.Never)]
public IEnumerable<Control> Containers => _owner.GetRealizedTreeContainers(); public IEnumerable<Control> Containers => _owner.GetRealizedTreeContainers();
[Obsolete("Use TreeView.TreeContainerFromItem")] [Obsolete("Use TreeView.TreeContainerFromItem"), EditorBrowsable(EditorBrowsableState.Never)]
public Control? ContainerFromItem(object item) => _owner.TreeContainerFromItem(item); public Control? ContainerFromItem(object item) => _owner.TreeContainerFromItem(item);
[Obsolete("Use TreeView.TreeItemFromContainer")] [Obsolete("Use TreeView.TreeItemFromContainer"), EditorBrowsable(EditorBrowsableState.Never)]
public object? ItemFromContainer(Control container) => _owner.TreeItemFromContainer(container); public object? ItemFromContainer(Control container) => _owner.TreeItemFromContainer(container);
} }
} }

3
src/Avalonia.Controls/ItemsControl.cs

@ -2,6 +2,7 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel;
using Avalonia.Automation.Peers; using Avalonia.Automation.Peers;
using Avalonia.Controls.Generators; using Avalonia.Controls.Generators;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
@ -626,7 +627,7 @@ namespace Avalonia.Controls
/// TreeView to be able to create a <see cref="TreeItemContainerGenerator"/>. Can be /// TreeView to be able to create a <see cref="TreeItemContainerGenerator"/>. Can be
/// removed in 12.0. /// removed in 12.0.
/// </remarks> /// </remarks>
[Obsolete] [Obsolete, EditorBrowsable(EditorBrowsableState.Never)]
private protected virtual ItemContainerGenerator CreateItemContainerGenerator() private protected virtual ItemContainerGenerator CreateItemContainerGenerator()
{ {
return new ItemContainerGenerator(this); return new ItemContainerGenerator(this);

3
src/Avalonia.Controls/Platform/Dialogs/ISystemDialogImpl.cs

@ -1,4 +1,5 @@
using System; using System;
using System.ComponentModel;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Metadata; using Avalonia.Metadata;
@ -7,7 +8,7 @@ namespace Avalonia.Controls.Platform
/// <summary> /// <summary>
/// Defines a platform-specific system dialog implementation. /// Defines a platform-specific system dialog implementation.
/// </summary> /// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API")] [Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
[Unstable] [Unstable]
public interface ISystemDialogImpl public interface ISystemDialogImpl
{ {

3
src/Avalonia.Controls/Platform/Dialogs/SystemDialogImpl.cs

@ -1,4 +1,5 @@
using System; using System;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Platform.Storage; using Avalonia.Platform.Storage;
@ -10,7 +11,7 @@ namespace Avalonia.Controls.Platform
/// <summary> /// <summary>
/// Defines a platform-specific system dialog implementation. /// Defines a platform-specific system dialog implementation.
/// </summary> /// </summary>
[Obsolete] [Obsolete, EditorBrowsable(EditorBrowsableState.Never)]
internal class SystemDialogImpl : ISystemDialogImpl internal class SystemDialogImpl : ISystemDialogImpl
{ {
public async Task<string[]?> ShowFileDialogAsync(FileDialog dialog, Window parent) public async Task<string[]?> ShowFileDialogAsync(FileDialog dialog, Window parent)

6
src/Avalonia.Controls/Platform/ManagedDispatcherImpl.cs

@ -58,6 +58,10 @@ public class ManagedDispatcherImpl : IControlledDispatcherImpl
public void RunLoop(CancellationToken token) public void RunLoop(CancellationToken token)
{ {
CancellationTokenRegistration registration = default;
if (token.CanBeCanceled)
registration = token.Register(() => _wakeup.Set());
while (!token.IsCancellationRequested) while (!token.IsCancellationRequested)
{ {
bool signaled; bool signaled;
@ -105,5 +109,7 @@ public class ManagedDispatcherImpl : IControlledDispatcherImpl
else else
_wakeup.WaitOne(); _wakeup.WaitOne();
} }
registration.Dispose();
} }
} }

5
src/Avalonia.Controls/Platform/Screen.cs

@ -1,4 +1,5 @@
using System; using System;
using System.ComponentModel;
namespace Avalonia.Platform namespace Avalonia.Platform
{ {
@ -17,7 +18,7 @@ namespace Avalonia.Platform
public double Scaling { get; } public double Scaling { get; }
/// <inheritdoc cref="Scaling"/> /// <inheritdoc cref="Scaling"/>
[Obsolete("Use the Scaling property instead.")] [Obsolete("Use the Scaling property instead."), EditorBrowsable(EditorBrowsableState.Never)]
public double PixelDensity => Scaling; public double PixelDensity => Scaling;
/// <summary> /// <summary>
@ -43,7 +44,7 @@ namespace Avalonia.Platform
public bool IsPrimary { get; } public bool IsPrimary { get; }
/// <inheritdoc cref="IsPrimary"/> /// <inheritdoc cref="IsPrimary"/>
[Obsolete("Use the IsPrimary property instead.")] [Obsolete("Use the IsPrimary property instead."), EditorBrowsable(EditorBrowsableState.Never)]
public bool Primary => IsPrimary; public bool Primary => IsPrimary;
/// <summary> /// <summary>

4
src/Avalonia.Controls/Primitives/Popup.cs

@ -74,7 +74,7 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Defines the <see cref="PlacementMode"/> property. /// Defines the <see cref="PlacementMode"/> property.
/// </summary> /// </summary>
[Obsolete("Use the Placement property instead.")] [Obsolete("Use the Placement property instead."), EditorBrowsable(EditorBrowsableState.Never)]
public static readonly StyledProperty<PlacementMode> PlacementModeProperty = PlacementProperty; public static readonly StyledProperty<PlacementMode> PlacementModeProperty = PlacementProperty;
/// <summary> /// <summary>
@ -241,7 +241,7 @@ namespace Avalonia.Controls.Primitives
} }
/// <inheritdoc cref="Placement"/> /// <inheritdoc cref="Placement"/>
[Obsolete("Use the Placement property instead.")] [Obsolete("Use the Placement property instead."), EditorBrowsable(EditorBrowsableState.Never)]
public PlacementMode PlacementMode public PlacementMode PlacementMode
{ {
get => GetValue(PlacementProperty); get => GetValue(PlacementProperty);

19
src/Avalonia.Controls/Primitives/ToggleButton.cs

@ -1,4 +1,5 @@
using System; using System;
using System.ComponentModel;
using Avalonia.Automation.Peers; using Avalonia.Automation.Peers;
using Avalonia.Controls.Metadata; using Avalonia.Controls.Metadata;
using Avalonia.Data; using Avalonia.Data;
@ -28,7 +29,7 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Defines the <see cref="Checked"/> event. /// Defines the <see cref="Checked"/> event.
/// </summary> /// </summary>
[Obsolete("Use IsCheckedChangedEvent instead.")] [Obsolete("Use IsCheckedChangedEvent instead."), EditorBrowsable(EditorBrowsableState.Never)]
public static readonly RoutedEvent<RoutedEventArgs> CheckedEvent = public static readonly RoutedEvent<RoutedEventArgs> CheckedEvent =
RoutedEvent.Register<ToggleButton, RoutedEventArgs>( RoutedEvent.Register<ToggleButton, RoutedEventArgs>(
nameof(Checked), nameof(Checked),
@ -37,7 +38,7 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Defines the <see cref="Unchecked"/> event. /// Defines the <see cref="Unchecked"/> event.
/// </summary> /// </summary>
[Obsolete("Use IsCheckedChangedEvent instead.")] [Obsolete("Use IsCheckedChangedEvent instead."), EditorBrowsable(EditorBrowsableState.Never)]
public static readonly RoutedEvent<RoutedEventArgs> UncheckedEvent = public static readonly RoutedEvent<RoutedEventArgs> UncheckedEvent =
RoutedEvent.Register<ToggleButton, RoutedEventArgs>( RoutedEvent.Register<ToggleButton, RoutedEventArgs>(
nameof(Unchecked), nameof(Unchecked),
@ -46,7 +47,7 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Defines the <see cref="Unchecked"/> event. /// Defines the <see cref="Unchecked"/> event.
/// </summary> /// </summary>
[Obsolete("Use IsCheckedChangedEvent instead.")] [Obsolete("Use IsCheckedChangedEvent instead."), EditorBrowsable(EditorBrowsableState.Never)]
public static readonly RoutedEvent<RoutedEventArgs> IndeterminateEvent = public static readonly RoutedEvent<RoutedEventArgs> IndeterminateEvent =
RoutedEvent.Register<ToggleButton, RoutedEventArgs>( RoutedEvent.Register<ToggleButton, RoutedEventArgs>(
nameof(Indeterminate), nameof(Indeterminate),
@ -72,7 +73,7 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Raised when a <see cref="ToggleButton"/> is checked. /// Raised when a <see cref="ToggleButton"/> is checked.
/// </summary> /// </summary>
[Obsolete("Use IsCheckedChanged instead.")] [Obsolete("Use IsCheckedChanged instead."), EditorBrowsable(EditorBrowsableState.Never)]
public event EventHandler<RoutedEventArgs>? Checked public event EventHandler<RoutedEventArgs>? Checked
{ {
add => AddHandler(CheckedEvent, value); add => AddHandler(CheckedEvent, value);
@ -82,7 +83,7 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Raised when a <see cref="ToggleButton"/> is unchecked. /// Raised when a <see cref="ToggleButton"/> is unchecked.
/// </summary> /// </summary>
[Obsolete("Use IsCheckedChanged instead.")] [Obsolete("Use IsCheckedChanged instead."), EditorBrowsable(EditorBrowsableState.Never)]
public event EventHandler<RoutedEventArgs>? Unchecked public event EventHandler<RoutedEventArgs>? Unchecked
{ {
add => AddHandler(UncheckedEvent, value); add => AddHandler(UncheckedEvent, value);
@ -92,7 +93,7 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// Raised when a <see cref="ToggleButton"/> is neither checked nor unchecked. /// Raised when a <see cref="ToggleButton"/> is neither checked nor unchecked.
/// </summary> /// </summary>
[Obsolete("Use IsCheckedChanged instead.")] [Obsolete("Use IsCheckedChanged instead."), EditorBrowsable(EditorBrowsableState.Never)]
public event EventHandler<RoutedEventArgs>? Indeterminate public event EventHandler<RoutedEventArgs>? Indeterminate
{ {
add => AddHandler(IndeterminateEvent, value); add => AddHandler(IndeterminateEvent, value);
@ -168,7 +169,7 @@ namespace Avalonia.Controls.Primitives
/// Called when <see cref="IsChecked"/> becomes true. /// Called when <see cref="IsChecked"/> becomes true.
/// </summary> /// </summary>
/// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param> /// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param>
[Obsolete("Use OnIsCheckedChanged instead.")] [Obsolete("Use OnIsCheckedChanged instead."), EditorBrowsable(EditorBrowsableState.Never)]
protected virtual void OnChecked(RoutedEventArgs e) protected virtual void OnChecked(RoutedEventArgs e)
{ {
RaiseEvent(e); RaiseEvent(e);
@ -178,7 +179,7 @@ namespace Avalonia.Controls.Primitives
/// Called when <see cref="IsChecked"/> becomes false. /// Called when <see cref="IsChecked"/> becomes false.
/// </summary> /// </summary>
/// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param> /// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param>
[Obsolete("Use OnIsCheckedChanged instead.")] [Obsolete("Use OnIsCheckedChanged instead."), EditorBrowsable(EditorBrowsableState.Never)]
protected virtual void OnUnchecked(RoutedEventArgs e) protected virtual void OnUnchecked(RoutedEventArgs e)
{ {
RaiseEvent(e); RaiseEvent(e);
@ -188,7 +189,7 @@ namespace Avalonia.Controls.Primitives
/// Called when <see cref="IsChecked"/> becomes null. /// Called when <see cref="IsChecked"/> becomes null.
/// </summary> /// </summary>
/// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param> /// <param name="e">Event arguments for the routed event that is raised by the default implementation of this method.</param>
[Obsolete("Use OnIsCheckedChanged instead.")] [Obsolete("Use OnIsCheckedChanged instead."), EditorBrowsable(EditorBrowsableState.Never)]
protected virtual void OnIndeterminate(RoutedEventArgs e) protected virtual void OnIndeterminate(RoutedEventArgs e)
{ {
RaiseEvent(e); RaiseEvent(e);

3
src/Avalonia.Controls/Screens.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using Avalonia.Platform; using Avalonia.Platform;
@ -68,7 +69,7 @@ namespace Avalonia.Controls
/// </summary> /// </summary>
/// <param name="window">The window impl for which to retrieve the Screen.</param> /// <param name="window">The window impl for which to retrieve the Screen.</param>
/// <returns>The <see cref="Screen"/>.</returns> /// <returns>The <see cref="Screen"/>.</returns>
[Obsolete("Use ScreenFromWindow(WindowBase) overload.")] [Obsolete("Use ScreenFromWindow(WindowBase) overload."), EditorBrowsable(EditorBrowsableState.Never)]
public Screen? ScreenFromWindow(IWindowBaseImpl window) public Screen? ScreenFromWindow(IWindowBaseImpl window)
{ {
return _iScreenImpl.ScreenFromWindow(window); return _iScreenImpl.ScreenFromWindow(window);

15
src/Avalonia.Controls/SystemDialog.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls.Platform; using Avalonia.Controls.Platform;
@ -11,7 +12,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Base class for system file dialogs. /// Base class for system file dialogs.
/// </summary> /// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API")] [Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public abstract class FileDialog : FileSystemDialog public abstract class FileDialog : FileSystemDialog
{ {
/// <summary> /// <summary>
@ -29,7 +30,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Base class for system file and directory dialogs. /// Base class for system file and directory dialogs.
/// </summary> /// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API")] [Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public abstract class FileSystemDialog : SystemDialog public abstract class FileSystemDialog : SystemDialog
{ {
/// <summary> /// <summary>
@ -42,7 +43,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Represents a system dialog that prompts the user to select a location for saving a file. /// Represents a system dialog that prompts the user to select a location for saving a file.
/// </summary> /// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API")] [Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public class SaveFileDialog : FileDialog public class SaveFileDialog : FileDialog
{ {
/// <summary> /// <summary>
@ -91,7 +92,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Represents a system dialog that allows the user to select one or more files to open. /// Represents a system dialog that allows the user to select one or more files to open.
/// </summary> /// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API")] [Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public class OpenFileDialog : FileDialog public class OpenFileDialog : FileDialog
{ {
/// <summary> /// <summary>
@ -132,7 +133,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Represents a system dialog that allows the user to select a directory. /// Represents a system dialog that allows the user to select a directory.
/// </summary> /// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API")] [Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public class OpenFolderDialog : FileSystemDialog public class OpenFolderDialog : FileSystemDialog
{ {
/// <summary> /// <summary>
@ -167,7 +168,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Base class for system dialogs. /// Base class for system dialogs.
/// </summary> /// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API")] [Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public abstract class SystemDialog public abstract class SystemDialog
{ {
static SystemDialog() static SystemDialog()
@ -188,7 +189,7 @@ namespace Avalonia.Controls
/// <summary> /// <summary>
/// Represents a filter in an <see cref="OpenFileDialog"/> or an <see cref="SaveFileDialog"/>. /// Represents a filter in an <see cref="OpenFileDialog"/> or an <see cref="SaveFileDialog"/>.
/// </summary> /// </summary>
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API")] [Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public class FileDialogFilter public class FileDialogFilter
{ {
/// <summary> /// <summary>

26
src/Avalonia.Controls/TextBlock.cs

@ -7,7 +7,6 @@ using Avalonia.Layout;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.TextFormatting; using Avalonia.Media.TextFormatting;
using Avalonia.Metadata; using Avalonia.Metadata;
using Avalonia.Utilities;
namespace Avalonia.Controls namespace Avalonia.Controls
{ {
@ -565,7 +564,8 @@ namespace Avalonia.Controls
context.FillRectangle(background, new Rect(Bounds.Size)); context.FillRectangle(background, new Rect(Bounds.Size));
} }
var padding = Padding; var scale = LayoutHelper.GetLayoutScale(this);
var padding = LayoutHelper.RoundLayoutThickness(Padding, scale, scale);
var top = padding.Top; var top = padding.Top;
var textHeight = TextLayout.Bounds.Height; var textHeight = TextLayout.Bounds.Height;
@ -659,7 +659,6 @@ namespace Avalonia.Controls
protected override Size MeasureOverride(Size availableSize) protected override Size MeasureOverride(Size availableSize)
{ {
var scale = LayoutHelper.GetLayoutScale(this); var scale = LayoutHelper.GetLayoutScale(this);
var padding = LayoutHelper.RoundLayoutThickness(Padding, scale, scale); var padding = LayoutHelper.RoundLayoutThickness(Padding, scale, scale);
_constraint = availableSize.Deflate(padding); _constraint = availableSize.Deflate(padding);
@ -703,19 +702,24 @@ namespace Avalonia.Controls
} }
} }
var measuredSize = TextLayout.Bounds.Size.Inflate(padding); return TextLayout.Bounds.Size.Inflate(padding);
return measuredSize;
} }
protected override Size ArrangeOverride(Size finalSize) protected override Size ArrangeOverride(Size finalSize)
{ {
if (HasComplexContent) var scale = LayoutHelper.GetLayoutScale(this);
{ var padding = LayoutHelper.RoundLayoutThickness(Padding, scale, scale);
var scale = LayoutHelper.GetLayoutScale(this);
var padding = LayoutHelper.RoundLayoutThickness(Padding, scale, scale); //Fixes: #11019
if (finalSize.Width < _constraint.Width)
{
_textLayout?.Dispose();
_textLayout = null;
_constraint = finalSize.Deflate(padding);
}
if (HasComplexContent)
{
var currentY = padding.Top; var currentY = padding.Top;
foreach (var textLine in TextLayout.TextLines) foreach (var textLine in TextLayout.TextLines)
@ -730,7 +734,7 @@ namespace Avalonia.Controls
&& controlRun.Control is Control control) && controlRun.Control is Control control)
{ {
control.Arrange( control.Arrange(
new Rect(new Point(currentX, currentY), new Rect(new Point(currentX, currentY),
new Size(control.DesiredSize.Width, textLine.Height))); new Size(control.DesiredSize.Width, textLine.Height)));
} }

3
src/Avalonia.Controls/TreeView.cs

@ -3,6 +3,7 @@ using System;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Linq; using System.Linq;
using Avalonia.Collections; using Avalonia.Collections;
@ -715,7 +716,7 @@ namespace Avalonia.Controls
} }
} }
[Obsolete] [Obsolete, EditorBrowsable(EditorBrowsableState.Never)]
private protected override ItemContainerGenerator CreateItemContainerGenerator() private protected override ItemContainerGenerator CreateItemContainerGenerator()
{ {
return new TreeItemContainerGenerator(this); return new TreeItemContainerGenerator(this);

5
src/Avalonia.Dialogs/ManagedFileDialogExtensions.cs

@ -1,6 +1,7 @@
#nullable enable #nullable enable
using System; using System;
using System.ComponentModel;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls; using Avalonia.Controls;
@ -39,11 +40,11 @@ namespace Avalonia.Dialogs
return builder; return builder;
} }
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API")] [Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public static Task<string[]> ShowManagedAsync(this OpenFileDialog dialog, Window parent, public static Task<string[]> ShowManagedAsync(this OpenFileDialog dialog, Window parent,
ManagedFileDialogOptions? options = null) => ShowManagedAsync<Window>(dialog, parent, options); ManagedFileDialogOptions? options = null) => ShowManagedAsync<Window>(dialog, parent, options);
[Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API")] [Obsolete("Use Window.StorageProvider API or TopLevel.StorageProvider API"), EditorBrowsable(EditorBrowsableState.Never)]
public static async Task<string[]> ShowManagedAsync<TWindow>(this OpenFileDialog dialog, Window parent, public static async Task<string[]> ShowManagedAsync<TWindow>(this OpenFileDialog dialog, Window parent,
ManagedFileDialogOptions? options = null) where TWindow : Window, new() ManagedFileDialogOptions? options = null) where TWindow : Window, new()
{ {

12
src/Avalonia.Native/WindowImplBase.cs

@ -220,17 +220,17 @@ namespace Avalonia.Native
_parent.PositionChanged?.Invoke(position.ToAvaloniaPixelPoint()); _parent.PositionChanged?.Invoke(position.ToAvaloniaPixelPoint());
} }
void IAvnWindowBaseEvents.RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta) void IAvnWindowBaseEvents.RawMouseEvent(AvnRawMouseEventType type, ulong timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta)
{ {
_parent.RawMouseEvent(type, timeStamp, modifiers, point, delta); _parent.RawMouseEvent(type, timeStamp, modifiers, point, delta);
} }
int IAvnWindowBaseEvents.RawKeyEvent(AvnRawKeyEventType type, uint timeStamp, AvnInputModifiers modifiers, uint key) int IAvnWindowBaseEvents.RawKeyEvent(AvnRawKeyEventType type, ulong timeStamp, AvnInputModifiers modifiers, uint key)
{ {
return _parent.RawKeyEvent(type, timeStamp, modifiers, key).AsComBool(); return _parent.RawKeyEvent(type, timeStamp, modifiers, key).AsComBool();
} }
int IAvnWindowBaseEvents.RawTextInputEvent(uint timeStamp, string text) int IAvnWindowBaseEvents.RawTextInputEvent(ulong timeStamp, string text)
{ {
return _parent.RawTextInputEvent(timeStamp, text).AsComBool(); return _parent.RawTextInputEvent(timeStamp, text).AsComBool();
} }
@ -286,7 +286,7 @@ namespace Avalonia.Native
_native?.Activate(); _native?.Activate();
} }
public bool RawTextInputEvent(uint timeStamp, string text) public bool RawTextInputEvent(ulong timeStamp, string text)
{ {
if (_inputRoot is null) if (_inputRoot is null)
return false; return false;
@ -300,7 +300,7 @@ namespace Avalonia.Native
return args.Handled; return args.Handled;
} }
public bool RawKeyEvent(AvnRawKeyEventType type, uint timeStamp, AvnInputModifiers modifiers, uint key) public bool RawKeyEvent(AvnRawKeyEventType type, ulong timeStamp, AvnInputModifiers modifiers, uint key)
{ {
if (_inputRoot is null) if (_inputRoot is null)
return false; return false;
@ -319,7 +319,7 @@ namespace Avalonia.Native
return false; return false;
} }
public void RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta) public void RawMouseEvent(AvnRawMouseEventType type, ulong timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta)
{ {
if (_inputRoot is null) if (_inputRoot is null)
return; return;

7
src/Avalonia.Native/avn.idl

@ -1,6 +1,7 @@
@clr-namespace Avalonia.Native.Interop @clr-namespace Avalonia.Native.Interop
@clr-access internal @clr-access internal
@clr-map bool int @clr-map bool int
@clr-map u_int64_t ulong
@cpp-preamble @@ @cpp-preamble @@
#pragma once #pragma once
#include "com.h" #include "com.h"
@ -583,12 +584,12 @@ interface IAvnWindowBaseEvents : IUnknown
void Resized([const] AvnSize& size, AvnPlatformResizeReason reason); void Resized([const] AvnSize& size, AvnPlatformResizeReason reason);
void PositionChanged(AvnPoint position); void PositionChanged(AvnPoint position);
void RawMouseEvent(AvnRawMouseEventType type, void RawMouseEvent(AvnRawMouseEventType type,
uint timeStamp, u_int64_t timeStamp,
AvnInputModifiers modifiers, AvnInputModifiers modifiers,
AvnPoint point, AvnPoint point,
AvnVector delta); AvnVector delta);
bool RawKeyEvent(AvnRawKeyEventType type, uint timeStamp, AvnInputModifiers modifiers, uint key); bool RawKeyEvent(AvnRawKeyEventType type, u_int64_t timeStamp, AvnInputModifiers modifiers, uint key);
bool RawTextInputEvent(uint timeStamp, [const] char* text); bool RawTextInputEvent(u_int64_t timeStamp, [const] char* text);
void ScalingChanged(double scaling); void ScalingChanged(double scaling);
void RunRenderPriorityJobs(); void RunRenderPriorityJobs();
void LostFocus(); void LostFocus();

4
src/Avalonia.OpenGL/Controls/OpenGlControlBase.cs

@ -8,6 +8,8 @@ using Avalonia.Rendering;
using Avalonia.Rendering.Composition; using Avalonia.Rendering.Composition;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using Avalonia.Platform; using Avalonia.Platform;
using System.ComponentModel;
namespace Avalonia.OpenGL.Controls namespace Avalonia.OpenGL.Controls
{ {
public abstract class OpenGlControlBase : Control public abstract class OpenGlControlBase : Control
@ -217,7 +219,7 @@ namespace Avalonia.OpenGL.Controls
return true; return true;
} }
[Obsolete("Use RequestNextFrameRendering()")] [Obsolete("Use RequestNextFrameRendering()"), EditorBrowsable(EditorBrowsableState.Never)]
// ReSharper disable once MemberCanBeProtected.Global // ReSharper disable once MemberCanBeProtected.Global
public new void InvalidateVisual() => RequestNextFrameRendering(); public new void InvalidateVisual() => RequestNextFrameRendering();

2
src/Browser/Avalonia.Browser/webapp/modules/avalonia/input.ts

@ -266,7 +266,7 @@ export class InputHelper {
} }
public static setCursor(inputElement: HTMLInputElement, kind: string) { public static setCursor(inputElement: HTMLInputElement, kind: string) {
if (kind === "pointer") { if (kind === "default") {
inputElement.style.removeProperty("cursor"); inputElement.style.removeProperty("cursor");
} else { } else {
inputElement.style.cursor = kind; inputElement.style.cursor = kind;

7
src/Directory.Build.props

@ -3,10 +3,5 @@
<Import Project="..\build\SharedVersion.props" /> <Import Project="..\build\SharedVersion.props" />
<Import Project="..\build\SourceLink.props" Condition="'$(DisableSourceLink)' == ''" /> <Import Project="..\build\SourceLink.props" Condition="'$(DisableSourceLink)' == ''" />
<Import Project="..\build\NetAnalyzers.props"/> <Import Project="..\build\NetAnalyzers.props"/>
<ItemGroup> <Import Project="..\build\ExternalConsumers.props"/>
<Compile Include="$(MSBuildThisFileDirectory)\Shared\ModuleInitializer.cs" >
<Link>Shared\_ModuleInitializer.cs</Link>
<Visible>false</Visible>
</Compile>
</ItemGroup>
</Project> </Project>

1
src/Windows/Avalonia.Win32/Avalonia.Win32.csproj

@ -20,7 +20,6 @@
<Import Project="..\..\..\build\DevAnalyzers.props" /> <Import Project="..\..\..\build\DevAnalyzers.props" />
<Import Project="..\..\..\build\SourceGenerators.props" /> <Import Project="..\..\..\build\SourceGenerators.props" />
<ItemGroup> <ItemGroup>
<Compile Remove="..\..\Shared\ModuleInitializer.cs" />
<Compile Remove="..\..\Shared\SourceGeneratorAttributes.cs" /> <Compile Remove="..\..\Shared\SourceGeneratorAttributes.cs" />
</ItemGroup> </ItemGroup>
<Import Project="..\..\..\build\TrimmingEnable.props" /> <Import Project="..\..\..\build\TrimmingEnable.props" />

44
tests/Avalonia.Base.UnitTests/DispatcherTests.cs

@ -3,6 +3,8 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using Avalonia.Controls.Platform;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.Utilities; using Avalonia.Utilities;
using Xunit; using Xunit;
@ -458,4 +460,46 @@ public class DispatcherTests
} }
} }
[Fact]
public void DispatcherInvokeAsyncUnwrapsTasks()
{
int asyncMethodStage = 0;
async Task AsyncMethod()
{
asyncMethodStage = 1;
await Task.Delay(200);
asyncMethodStage = 2;
}
async Task<int> AsyncMethodWithResult()
{
await Task.Delay(100);
return 1;
}
async Task Test()
{
await Dispatcher.UIThread.InvokeAsync(AsyncMethod);
Assert.Equal(2, asyncMethodStage);
Assert.Equal(1, await Dispatcher.UIThread.InvokeAsync(AsyncMethodWithResult));
asyncMethodStage = 0;
await Dispatcher.UIThread.InvokeAsync(AsyncMethod, DispatcherPriority.Default);
Assert.Equal(2, asyncMethodStage);
Assert.Equal(1, await Dispatcher.UIThread.InvokeAsync(AsyncMethodWithResult, DispatcherPriority.Default));
Dispatcher.UIThread.ExitAllFrames();
}
using (new DispatcherServices(new ManagedDispatcherImpl(null)))
{
var t = Test();
var cts = new CancellationTokenSource();
Task.Delay(3000).ContinueWith(_ => cts.Cancel());
Dispatcher.UIThread.MainLoop(cts.Token);
Assert.True(t.IsCompletedSuccessfully);
t.GetAwaiter().GetResult();
}
}
} }

27
tests/Avalonia.Skia.UnitTests/Media/TextFormatting/TextLineTests.cs

@ -1021,6 +1021,33 @@ namespace Avalonia.Skia.UnitTests.Media.TextFormatting
} }
} }
[Fact]
public void Should_GetTextBounds_With_EndOfParagraph()
{
var text = "abc";
using (Start())
{
var defaultProperties = new GenericTextRunProperties(Typeface.Default);
var textSource = new SingleBufferTextSource(text, defaultProperties, true);
var formatter = new TextFormatterImpl();
var textLine =
formatter.FormatLine(textSource, 0, double.PositiveInfinity,
new GenericTextParagraphProperties(FlowDirection.LeftToRight, TextAlignment.Left,
true, true, defaultProperties, TextWrapping.NoWrap, 0, 0, 0));
var textBounds = textLine.GetTextBounds(3, 1);
Assert.Equal(1, textBounds.Count);
var firstBounds = textBounds.First();
Assert.True(firstBounds.TextRunBounds.Count > 0);
}
}
private class FixedRunsTextSource : ITextSource private class FixedRunsTextSource : ITextSource
{ {
private readonly IReadOnlyList<TextRun> _textRuns; private readonly IReadOnlyList<TextRun> _textRuns;

Loading…
Cancel
Save