diff --git a/Directory.Packages.props b/Directory.Packages.props index 176c4b731c..da5809c36d 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -7,7 +7,7 @@ - + diff --git a/build/SampleApp.props b/build/SampleApp.props index 6816a38cbe..e8a9b9166e 100644 --- a/build/SampleApp.props +++ b/build/SampleApp.props @@ -14,7 +14,7 @@ - + diff --git a/external/XamlX b/external/XamlX index 86f5a26fad..d7e37ca63d 160000 --- a/external/XamlX +++ b/external/XamlX @@ -1 +1 @@ -Subproject commit 86f5a26fadb745e95169c3c805ebd9fd7c9b44d2 +Subproject commit d7e37ca63dc9b13cdc95ca165938d4904fa0eddf diff --git a/samples/AppWithoutLifetime/Program.cs b/samples/AppWithoutLifetime/Program.cs index 60ab32824e..80be3f76bd 100644 --- a/samples/AppWithoutLifetime/Program.cs +++ b/samples/AppWithoutLifetime/Program.cs @@ -24,6 +24,8 @@ class Program public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() +#if DEBUG .WithDeveloperTools() +#endif .LogToTrace(); } diff --git a/samples/BindingDemo/App.xaml.cs b/samples/BindingDemo/App.xaml.cs index e76f61ac63..d6ba950382 100644 --- a/samples/BindingDemo/App.xaml.cs +++ b/samples/BindingDemo/App.xaml.cs @@ -24,7 +24,9 @@ namespace BindingDemo public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() +#if DEBUG .WithDeveloperTools() +#endif .LogToTrace(); } } diff --git a/samples/ControlCatalog.Desktop/NativeControls/Gtk/EmbedSample.Gtk.cs b/samples/ControlCatalog.Desktop/NativeControls/Gtk/EmbedSample.Gtk.cs index 523503cc38..e02b1b7428 100644 --- a/samples/ControlCatalog.Desktop/NativeControls/Gtk/EmbedSample.Gtk.cs +++ b/samples/ControlCatalog.Desktop/NativeControls/Gtk/EmbedSample.Gtk.cs @@ -21,10 +21,11 @@ public class EmbedSampleGtk : INativeDemoControl } var control = createDefault(); - var nodes = Path.GetFullPath(Path.Combine(typeof(EmbedSample).Assembly.GetModules()[0].FullyQualifiedName, - "..", "NativeControls", "Gtk", "nodes.mp4")); + var nodesFile = Path.Combine(AppContext.BaseDirectory, "NativeControls", "Gtk", "nodes.mp4"); + nodesFile = Path.GetFullPath(nodesFile); + _mplayer = Process.Start(new ProcessStartInfo("mplayer", - $"-vo x11 -zoom -loop 0 -wid {control.Handle.ToInt64()} \"{nodes}\"") + $"-vo x11 -zoom -loop 0 -wid {control.Handle.ToInt64()} \"{nodesFile}\"") { UseShellExecute = false, diff --git a/samples/ControlCatalog.Desktop/Program.cs b/samples/ControlCatalog.Desktop/Program.cs index 819072db18..1f553d116e 100644 --- a/samples/ControlCatalog.Desktop/Program.cs +++ b/samples/ControlCatalog.Desktop/Program.cs @@ -162,7 +162,9 @@ namespace ControlCatalog.Desktop }) .UseSkia() .WithInterFont() +#if DEBUG .WithDeveloperTools() +#endif .AfterSetup(builder => { EmbedSample.Implementation = OperatingSystem.IsWindows() ? new EmbedSampleWin() diff --git a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs index 295aa9d139..1624fc563f 100644 --- a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs +++ b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml.cs @@ -102,8 +102,8 @@ namespace ControlCatalog.Pages return String.Format("{0} ({1})", parts.ToArray()); }); var binding = new MultiBinding { Converter = converter }; - binding.Bindings.Add(new Binding("Name")); - binding.Bindings.Add(new Binding("Abbreviation")); + binding.Bindings.Add(CompiledBinding.Create(s => s.Name)); + binding.Bindings.Add(CompiledBinding.Create(s => s.Abbreviation)); MultiBindingBox.ValueMemberBinding = binding; diff --git a/samples/ControlCatalog/Pages/CarouselPage/CareCompanionAppPage.xaml.cs b/samples/ControlCatalog/Pages/CarouselPage/CareCompanionAppPage.xaml.cs index bc8be3ea87..16f1ba0ddc 100644 --- a/samples/ControlCatalog/Pages/CarouselPage/CareCompanionAppPage.xaml.cs +++ b/samples/ControlCatalog/Pages/CarouselPage/CareCompanionAppPage.xaml.cs @@ -5,6 +5,7 @@ using Avalonia.Animation; using Avalonia.Controls; using Avalonia.Controls.Presenters; using Avalonia.Controls.Primitives; +using Avalonia.Data; using Avalonia.Input; using Avalonia.Interactivity; using Avalonia.Layout; @@ -130,7 +131,7 @@ public partial class CareCompanionAppPage : UserControl }; pager.Bind(PipsPager.SelectedPageIndexProperty, - new Avalonia.Data.Binding("SelectedIndex") { Source = carousel, Mode = Avalonia.Data.BindingMode.TwoWay }); + CompiledBinding.Create(c => c.SelectedIndex, carousel, mode: BindingMode.TwoWay)); return pager; } diff --git a/samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs b/samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs index b2a91da381..dcffeb611e 100644 --- a/samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs +++ b/samples/ControlCatalog/Pages/DragAndDropPage.xaml.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using System.Linq; using System.Reflection; using System.Threading.Tasks; @@ -38,9 +39,11 @@ namespace ControlCatalog.Pages "Files", async d => { - if (Assembly.GetEntryAssembly()?.GetModules().FirstOrDefault()?.FullyQualifiedName is { } name && + var currentFile = Environment.ProcessPath; + + if (File.Exists(currentFile) && TopLevel.GetTopLevel(this) is { } topLevel && - await topLevel.StorageProvider.TryGetFileFromPathAsync(name) is { } storageFile) + await topLevel.StorageProvider.TryGetFileFromPathAsync(currentFile) is { } storageFile) { d.Add(DataTransferItem.Create(DataFormat.File, storageFile)); } diff --git a/samples/ControlCatalog/Pages/NotificationsPage.xaml b/samples/ControlCatalog/Pages/NotificationsPage.xaml index 2ae1db7d43..61d8afdea4 100644 --- a/samples/ControlCatalog/Pages/NotificationsPage.xaml +++ b/samples/ControlCatalog/Pages/NotificationsPage.xaml @@ -17,11 +17,7 @@ XAML only notification manager. + Content="Show XAML only Notification" Click="ShowNotification" /> diff --git a/samples/ControlCatalog/Pages/NotificationsPage.xaml.cs b/samples/ControlCatalog/Pages/NotificationsPage.xaml.cs index 5ff67e10dc..cc1ad3481c 100644 --- a/samples/ControlCatalog/Pages/NotificationsPage.xaml.cs +++ b/samples/ControlCatalog/Pages/NotificationsPage.xaml.cs @@ -1,6 +1,7 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Notifications; +using Avalonia.Interactivity; using ControlCatalog.ViewModels; namespace ControlCatalog.Pages @@ -25,9 +26,14 @@ namespace ControlCatalog.Pages _viewModel.NotificationManager = new WindowNotificationManager(TopLevel.GetTopLevel(this)!); } - public void NotificationOnClick() + private void ShowNotification(object? sender, RoutedEventArgs e) { - ControlNotifications.Show("Notification clicked"); + ControlNotifications.Show(new Notification + { + OnClick = () => ControlNotifications.Show("Notification clicked"), + Title = "Title", + Message = "Message" + }); } } } diff --git a/samples/GpuInterop/Program.cs b/samples/GpuInterop/Program.cs index 46cf738304..8bfddfdf5e 100644 --- a/samples/GpuInterop/Program.cs +++ b/samples/GpuInterop/Program.cs @@ -34,7 +34,9 @@ namespace GpuInterop UseDebug = true } }) +#if DEBUG .WithDeveloperTools() +#endif .LogToTrace(LogEventLevel.Debug, "Vulkan"); } } diff --git a/samples/IntegrationTestApp/Program.cs b/samples/IntegrationTestApp/Program.cs index 29b7557f6a..c2655178cd 100644 --- a/samples/IntegrationTestApp/Program.cs +++ b/samples/IntegrationTestApp/Program.cs @@ -31,7 +31,9 @@ namespace IntegrationTestApp public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() +#if DEBUG .WithDeveloperTools() +#endif .AfterSetup(builder => { NativeTextBox.Factory = diff --git a/samples/RenderDemo/App.xaml.cs b/samples/RenderDemo/App.xaml.cs index e08c48475b..b1e44a2e96 100644 --- a/samples/RenderDemo/App.xaml.cs +++ b/samples/RenderDemo/App.xaml.cs @@ -31,7 +31,9 @@ namespace RenderDemo OverlayPopups = true, }) .UsePlatformDetect() - .WithDeveloperTools() +#if DEBUG + .WithDeveloperTools() +#endif .LogToTrace(); } } diff --git a/samples/SafeAreaDemo.Desktop/Program.cs b/samples/SafeAreaDemo.Desktop/Program.cs index 05593b3313..f8d86a8c00 100644 --- a/samples/SafeAreaDemo.Desktop/Program.cs +++ b/samples/SafeAreaDemo.Desktop/Program.cs @@ -16,7 +16,9 @@ namespace SafeAreaDemo.Desktop public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() +#if DEBUG .WithDeveloperTools() +#endif .LogToTrace(); } } diff --git a/samples/Sandbox/Program.cs b/samples/Sandbox/Program.cs index b676992111..551d6deb23 100644 --- a/samples/Sandbox/Program.cs +++ b/samples/Sandbox/Program.cs @@ -10,7 +10,9 @@ namespace Sandbox public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() +#if DEBUG .WithDeveloperTools() +#endif .LogToTrace(); } } diff --git a/samples/TextTestApp/Program.cs b/samples/TextTestApp/Program.cs index e3931f97d8..3fc3ee2bcd 100644 --- a/samples/TextTestApp/Program.cs +++ b/samples/TextTestApp/Program.cs @@ -23,7 +23,9 @@ namespace TextTestApp { return AppBuilder.Configure() .UsePlatformDetect() +#if DEBUG .WithDeveloperTools() +#endif .LogToTrace(); } } diff --git a/samples/VirtualizationDemo/Program.cs b/samples/VirtualizationDemo/Program.cs index dd289b3b25..2bed2ba006 100644 --- a/samples/VirtualizationDemo/Program.cs +++ b/samples/VirtualizationDemo/Program.cs @@ -7,7 +7,9 @@ class Program public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() .UsePlatformDetect() +#if DEBUG .WithDeveloperTools() +#endif .LogToTrace(); public static int Main(string[] args) diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaRuntimeXamlLoader.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaRuntimeXamlLoader.cs index eb153f7d0c..b4d26b7134 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaRuntimeXamlLoader.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaRuntimeXamlLoader.cs @@ -21,7 +21,8 @@ namespace Avalonia.Markup.Xaml /// The URI of the XAML being loaded. /// Indicates whether the XAML is being loaded in design mode. /// The loaded object. - [RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)] + [RequiresUnreferencedCode(XamlX.TrimmingMessages.Sre)] + [RequiresDynamicCode(XamlX.TrimmingMessages.Sre)] public static object Load([StringSyntax(StringSyntaxAttribute.Xml)] string xaml, Assembly? localAssembly = null, object? rootInstance = null, Uri? uri = null, bool designMode = false) { xaml = xaml ?? throw new ArgumentNullException(nameof(xaml)); @@ -41,7 +42,8 @@ namespace Avalonia.Markup.Xaml /// The URI of the XAML being loaded. /// Indicates whether the XAML is being loaded in design mode. /// The loaded object. - [RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)] + [RequiresUnreferencedCode(XamlX.TrimmingMessages.Sre)] + [RequiresDynamicCode(XamlX.TrimmingMessages.Sre)] public static object Load(Stream stream, Assembly? localAssembly = null, object? rootInstance = null, Uri? uri = null, bool designMode = false) => AvaloniaXamlIlRuntimeCompiler.Load(new RuntimeXamlLoaderDocument(uri, rootInstance, stream), @@ -53,7 +55,8 @@ namespace Avalonia.Markup.Xaml /// The stream containing the XAML. /// Xaml loader configuration. /// The loaded object. - [RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)] + [RequiresUnreferencedCode(XamlX.TrimmingMessages.Sre)] + [RequiresDynamicCode(XamlX.TrimmingMessages.Sre)] public static object Load(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration? configuration = null) => AvaloniaXamlIlRuntimeCompiler.Load(document, configuration ?? new RuntimeXamlLoaderConfiguration()); @@ -63,7 +66,8 @@ namespace Avalonia.Markup.Xaml /// Collection of documents. /// Xaml loader configuration. /// The loaded objects per each input document. If document was removed, the element by index is null. - [RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)] + [RequiresUnreferencedCode(XamlX.TrimmingMessages.Sre)] + [RequiresDynamicCode(XamlX.TrimmingMessages.Sre)] public static IReadOnlyList LoadGroup(IReadOnlyCollection documents, RuntimeXamlLoaderConfiguration? configuration = null) => AvaloniaXamlIlRuntimeCompiler.LoadGroup(documents, configuration ?? new RuntimeXamlLoaderConfiguration()); @@ -73,7 +77,8 @@ namespace Avalonia.Markup.Xaml /// The string containing the XAML. /// Default assembly for clr-namespace:. /// The loaded object. - [RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)] + [RequiresUnreferencedCode(XamlX.TrimmingMessages.Sre)] + [RequiresDynamicCode(XamlX.TrimmingMessages.Sre)] public static object Parse([StringSyntax(StringSyntaxAttribute.Xml)] string xaml, Assembly? localAssembly = null) => Load(xaml, localAssembly); @@ -84,7 +89,8 @@ namespace Avalonia.Markup.Xaml /// >The string containing the XAML. /// >Default assembly for clr-namespace:. /// The loaded object. - [RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)] + [RequiresUnreferencedCode(XamlX.TrimmingMessages.Sre)] + [RequiresDynamicCode(XamlX.TrimmingMessages.Sre)] public static T Parse<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.All)] T>([StringSyntax(StringSyntaxAttribute.Xml)] string xaml, Assembly? localAssembly = null) => (T)Parse(xaml, localAssembly); } diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs index 728fdb397a..d631cdccd1 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs @@ -28,7 +28,8 @@ using XamlX.IL.Cecil; namespace Avalonia.Markup.Xaml.XamlIl { #if !RUNTIME_XAML_CECIL - [RequiresUnreferencedCode(XamlX.TrimmingMessages.DynamicXamlReference)] + [RequiresUnreferencedCode(XamlX.TrimmingMessages.Sre)] + [RequiresDynamicCode(XamlX.TrimmingMessages.Sre)] #endif internal static class AvaloniaXamlIlRuntimeCompiler { @@ -41,30 +42,8 @@ namespace Avalonia.Markup.Xaml.XamlIl private static XamlLanguageEmitMappings? _sreEmitMappings; private static XamlXmlnsMappings? _sreXmlns; private static AssemblyBuilder? _sreAsm; - private static bool _sreCanSave; - - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = XamlX.TrimmingMessages.CanBeSafelyTrimmed)] - public static void DumpRuntimeCompilationResults() - { - if (_sreBuilder == null) - return; - var saveMethod = _sreAsm!.GetType().GetMethods() - .FirstOrDefault(m => m.Name == "Save" && m.GetParameters().Length == 1); - if (saveMethod == null) - return; - try - { - _sreBuilder.CreateGlobalFunctions(); - saveMethod.Invoke(_sreAsm, new Object[] {"XamlIlLoader.ildump"}); - } - catch - { - //Ignore - } - } [CompilerDynamicDependencies] - [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = XamlX.TrimmingMessages.GeneratedTypes)] [MemberNotNull(nameof(_sreTypeSystem))] [MemberNotNull(nameof(_sreBuilder))] [MemberNotNull(nameof(_sreMappings))] @@ -74,7 +53,7 @@ namespace Avalonia.Markup.Xaml.XamlIl [MemberNotNull(nameof(_ignoresAccessChecksFromAttribute))] static void InitializeSre() { - // SRE backend doesn't load assemblies, unless they are already in the memory. + // SRE backend doesn't load assemblies unless they are already in the memory. // At the very least, we should make sure that assemblies necessary for `AvaloniaXamlIlWellKnownTypes` are loaded. // Root `Avalonia.Controls`. GC.KeepAlive(typeof(Avalonia.Controls.Control)); @@ -87,26 +66,10 @@ namespace Avalonia.Markup.Xaml.XamlIl _sreTypeSystem = new SreTypeSystem(); if (_sreBuilder == null) { - _sreCanSave = !(RuntimeInformation.FrameworkDescription.StartsWith(".NET Core")); var name = new AssemblyName(Guid.NewGuid().ToString("N")); - if (_sreCanSave) - { - var define = GetDefineDynamicAssembly(); - if (define != null) - _sreAsm = (AssemblyBuilder)define.Invoke(AppDomain.CurrentDomain, new object[] - { - name, (AssemblyBuilderAccess)3, - Path.GetDirectoryName(typeof(AvaloniaXamlIlRuntimeCompiler).Assembly.GetModules()[0] - .FullyQualifiedName)! - })!; - else - _sreCanSave = false; - } - - if(_sreAsm == null) - _sreAsm = AssemblyBuilder.DefineDynamicAssembly(name, - AssemblyBuilderAccess.RunAndCollect); - + + _sreAsm ??= AssemblyBuilder.DefineDynamicAssembly(name, AssemblyBuilderAccess.RunAndCollect); + _sreBuilder = _sreAsm.DefineDynamicModule("XamlIlLoader.ildump"); } @@ -123,12 +86,6 @@ namespace Avalonia.Markup.Xaml.XamlIl _ignoresAccessChecksFromAttribute = EmitIgnoresAccessCheckAttributeDefinition(_sreBuilder); } - [UnconditionalSuppressMessage("Trimming", "IL2026", Justification = XamlX.TrimmingMessages.CanBeSafelyTrimmed)] - static MethodInfo? GetDefineDynamicAssembly() => AppDomain.CurrentDomain.GetType().GetMethods() - .FirstOrDefault(m => m.Name == "DefineDynamicAssembly" - && m.GetParameters().Length == 3 && - m.GetParameters()[2].ParameterType == typeof(string)); - static Type EmitIgnoresAccessCheckAttributeDefinition(ModuleBuilder builder) { var tb = builder.DefineType("System.Runtime.CompilerServices.IgnoresAccessChecksToAttribute", @@ -237,37 +194,15 @@ namespace Avalonia.Markup.Xaml.XamlIl return result; } - static object LoadSre(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration) + public static object LoadSre(RuntimeXamlLoaderDocument document, RuntimeXamlLoaderConfiguration configuration) { - var success = false; - try - { - var rv = LoadSreCore(document, configuration); - success = true; - return rv; - } - finally - { - if(!success && _sreCanSave) - DumpRuntimeCompilationResults(); - } + return LoadSreCore(document, configuration); } - static IReadOnlyList LoadGroupSre(IReadOnlyCollection documents, + public static IReadOnlyList LoadGroupSre(IReadOnlyCollection documents, RuntimeXamlLoaderConfiguration configuration) { - var success = false; - try - { - var rv = LoadGroupSreCore(documents, configuration); - success = true; - return rv; - } - finally - { - if(!success && _sreCanSave) - DumpRuntimeCompilationResults(); - } + return LoadGroupSreCore(documents, configuration); } [UnconditionalSuppressMessage("Trimming", "IL2072", Justification = XamlX.TrimmingMessages.GeneratedTypes)]