diff --git a/Avalonia.sln.DotSettings b/Avalonia.sln.DotSettings index 7060f4a62a..25d62b0494 100644 --- a/Avalonia.sln.DotSettings +++ b/Avalonia.sln.DotSettings @@ -37,4 +37,5 @@ <Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /> <Policy Inspect="False" Prefix="T" Suffix="" Style="AaBb" /> <Policy Inspect="False" Prefix="" Suffix="" Style="AaBb" /> + True True \ No newline at end of file diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 721a0415f4..e67fa14c57 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -31,6 +31,8 @@ jobs: condition: not(canceled()) - job: macOS + variables: + SolutionDir: '$(Build.SourcesDirectory)' pool: vmImage: 'macOS-10.14' steps: @@ -97,6 +99,8 @@ jobs: - job: Windows pool: vmImage: 'windows-2019' + variables: + SolutionDir: '$(Build.SourcesDirectory)' steps: - task: UseDotNet@2 displayName: 'Use .NET Core SDK 3.1.401' diff --git a/build.ps1 b/build.ps1 index 57e2f80075..3672e82d3b 100644 --- a/build.ps1 +++ b/build.ps1 @@ -62,6 +62,8 @@ else { } else { ExecSafe { & $DotNetInstallFile -InstallDir $DotNetDirectory -Version $DotNetVersion -NoPath } } + + $env:PATH="$DotNetDirectory;$env:PATH" } Write-Output "Microsoft (R) .NET Core SDK version $(& $env:DOTNET_EXE --version)" diff --git a/build/Assets/Icon.png b/build/Assets/Icon.png new file mode 100644 index 0000000000..41a2a618fb Binary files /dev/null and b/build/Assets/Icon.png differ diff --git a/build/SharedVersion.props b/build/SharedVersion.props index d3cebef418..a5c0aa1bea 100644 --- a/build/SharedVersion.props +++ b/build/SharedVersion.props @@ -10,10 +10,17 @@ CS1591 latest MIT - https://avatars2.githubusercontent.com/u/14075148?s=200 + Icon.png Avalonia is a WPF/UWP-inspired cross-platform XAML-based UI framework providing a flexible styling system and supporting a wide range of Operating Systems such as Windows (.NET Framework, .NET Core), Linux (via Xorg), MacOS and with experimental support for Android and iOS. avalonia;avaloniaui;mvvm;rx;reactive extensions;android;ios;mac;forms;wpf;net;netstandard;net461;uwp;xamarin https://github.com/AvaloniaUI/Avalonia/releases git + $(MSBuildThisFileDirectory)\avalonia.snk + false + $(DefineConstants);SIGNED_BUILD + + + + diff --git a/build/SourceLink.props b/build/SourceLink.props index 0c9b6a34f8..e27727c9e8 100644 --- a/build/SourceLink.props +++ b/build/SourceLink.props @@ -1,5 +1,5 @@ - + - \ No newline at end of file + diff --git a/build/XUnit.props b/build/XUnit.props index 079565d184..a75e1bac86 100644 --- a/build/XUnit.props +++ b/build/XUnit.props @@ -11,4 +11,8 @@ + + $(MSBuildThisFileDirectory)\avalonia.snk + False + diff --git a/build/avalonia.snk b/build/avalonia.snk new file mode 100644 index 0000000000..10b49deb31 Binary files /dev/null and b/build/avalonia.snk differ diff --git a/dirs.proj b/dirs.proj index bf32abef72..594f2c22d3 100644 --- a/dirs.proj +++ b/dirs.proj @@ -21,6 +21,7 @@ + diff --git a/native/Avalonia.Native/src/OSX/window.mm b/native/Avalonia.Native/src/OSX/window.mm index fb945a105e..67b1ea50a6 100644 --- a/native/Avalonia.Native/src/OSX/window.mm +++ b/native/Avalonia.Native/src/OSX/window.mm @@ -1338,6 +1338,12 @@ NSArray* AllLoopModes = [NSArray arrayWithObjects: NSDefaultRunLoopMode, NSEvent } _parent->BaseEvents->RunRenderPriorityJobs(); + + if (_parent == nullptr) + { + return; + } + _parent->BaseEvents->Paint(); } diff --git a/nukebuild/BuildTasksPatcher.cs b/nukebuild/BuildTasksPatcher.cs index 44f01da669..e3766ae23f 100644 --- a/nukebuild/BuildTasksPatcher.cs +++ b/nukebuild/BuildTasksPatcher.cs @@ -29,7 +29,11 @@ public class BuildTasksPatcher InputAssemblies = new[] { temp, typeof(Mono.Cecil.AssemblyDefinition).Assembly.GetModules()[0] - .FullyQualifiedName + .FullyQualifiedName, + typeof(Mono.Cecil.Rocks.MethodBodyRocks).Assembly.GetModules()[0].FullyQualifiedName, + typeof(Mono.Cecil.Pdb.PdbReaderProvider).Assembly.GetModules()[0].FullyQualifiedName, + typeof(Mono.Cecil.Mdb.MdbReaderProvider).Assembly.GetModules()[0].FullyQualifiedName + }, SearchDirectories = new string[0], OutputFile = output diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj index b06e49f2eb..77cfb83427 100644 --- a/nukebuild/_build.csproj +++ b/nukebuild/_build.csproj @@ -16,7 +16,7 @@ - + diff --git a/packages/Avalonia/AvaloniaBuildTasks.targets b/packages/Avalonia/AvaloniaBuildTasks.targets index 84a62bb5c0..612c368633 100644 --- a/packages/Avalonia/AvaloniaBuildTasks.targets +++ b/packages/Avalonia/AvaloniaBuildTasks.targets @@ -87,6 +87,9 @@ ProjectDirectory="$(MSBuildProjectDirectory)" VerifyIl="$(AvaloniaXamlIlVerifyIl)" ReportImportance="$(AvaloniaXamlReportImportance)" + AssemblyOriginatorKeyFile="$(AssemblyOriginatorKeyFile)" + SignAssembly="$(SignAssembly)" + DelaySign="$(DelaySign)" /> () + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + desktop.MainWindow = new MainWindow(); + base.OnFrameworkInitializationCompleted(); + } + + public static int Main(string[] args) + => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); + + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() .UsePlatformDetect() .UseReactiveUI() - .LogToDebug() - .Start(); - } + .LogToTrace(); } } diff --git a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj index 1a112d0d7d..c6405dabb6 100644 --- a/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj +++ b/samples/ControlCatalog.Desktop/ControlCatalog.Desktop.csproj @@ -3,6 +3,7 @@ Exe net461 + x64 diff --git a/samples/ControlCatalog.Desktop/Program.cs b/samples/ControlCatalog.Desktop/Program.cs index b2df1953f5..5af646b180 100644 --- a/samples/ControlCatalog.Desktop/Program.cs +++ b/samples/ControlCatalog.Desktop/Program.cs @@ -10,19 +10,15 @@ namespace ControlCatalog internal class Program { [STAThread] - static void Main(string[] args) - { - // TODO: Make this work with GTK/Skia/Cairo depending on command-line args - // again. - BuildAvaloniaApp().Start(); - } + public static int Main(string[] args) + => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); /// /// This method is needed for IDE previewer infrastructure /// public static AppBuilder BuildAvaloniaApp() => AppBuilder.Configure() - .LogToDebug() + .LogToTrace() .UsePlatformDetect() .UseReactiveUI(); diff --git a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj index 28b0257eda..d5aedf7783 100644 --- a/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj +++ b/samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj @@ -11,9 +11,8 @@ - - + diff --git a/samples/ControlCatalog.NetCore/Program.cs b/samples/ControlCatalog.NetCore/Program.cs index 142736a0bb..675ea2e10f 100644 --- a/samples/ControlCatalog.NetCore/Program.cs +++ b/samples/ControlCatalog.NetCore/Program.cs @@ -7,12 +7,11 @@ using System.Threading.Tasks; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.ApplicationLifetimes; +using Avalonia.Dialogs; using Avalonia.Headless; using Avalonia.LogicalTree; -using Avalonia.Skia; using Avalonia.ReactiveUI; using Avalonia.Threading; -using Avalonia.Dialogs; namespace ControlCatalog.NetCore { @@ -121,7 +120,7 @@ namespace ControlCatalog.NetCore .UseSkia() .UseReactiveUI() .UseManagedSystemDialogs() - .LogToDebug(); + .LogToTrace(); static void SilenceConsole() { diff --git a/samples/ControlCatalog/App.xaml b/samples/ControlCatalog/App.xaml index 9bac320c79..6aad44c0d5 100644 --- a/samples/ControlCatalog/App.xaml +++ b/samples/ControlCatalog/App.xaml @@ -12,6 +12,16 @@ + + + diff --git a/samples/ControlCatalog/MainView.xaml b/samples/ControlCatalog/MainView.xaml index bd5beafe29..f001425964 100644 --- a/samples/ControlCatalog/MainView.xaml +++ b/samples/ControlCatalog/MainView.xaml @@ -44,6 +44,7 @@ ScrollViewer.HorizontalScrollBarVisibility="Disabled"> + diff --git a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml index a49616e543..1a53217842 100644 --- a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml +++ b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml @@ -1,5 +1,6 @@ AutoCompleteBox @@ -56,6 +57,16 @@ Width="200" Margin="0,0,0,8" FilterMode="None"/> + + + + + + + diff --git a/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml b/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml index c3f9f65dd9..4ac2330403 100644 --- a/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml +++ b/samples/ControlCatalog/Pages/ButtonSpinnerPage.xaml @@ -1,6 +1,7 @@  + x:Class="ControlCatalog.Pages.ButtonSpinnerPage" + xmlns:sys="clr-namespace:System;assembly=netstandard"> ButtonSpinner @@ -19,6 +20,14 @@ ShowButtonSpinner="{Binding #showSpinCheck.IsChecked}"> + + + + + + diff --git a/samples/ControlCatalog/Pages/ComboBoxPage.xaml b/samples/ControlCatalog/Pages/ComboBoxPage.xaml index 369f703718..025b85492c 100644 --- a/samples/ControlCatalog/Pages/ComboBoxPage.xaml +++ b/samples/ControlCatalog/Pages/ComboBoxPage.xaml @@ -1,6 +1,7 @@ + x:Class="ControlCatalog.Pages.ComboBoxPage" + xmlns:sys="clr-namespace:System;assembly=netstandard"> ComboBox A drop-down list. @@ -35,6 +36,16 @@ + + + Inline Items + Inline Item 2 + Inline Item 3 + Inline Item 4 + + + + diff --git a/samples/ControlCatalog/Pages/DateTimePickerPage.xaml b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml index af6b6e8605..45056a9a76 100644 --- a/samples/ControlCatalog/Pages/DateTimePickerPage.xaml +++ b/samples/ControlCatalog/Pages/DateTimePickerPage.xaml @@ -2,6 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" + xmlns:sys="clr-namespace:System;assembly=netstandard" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="ControlCatalog.Pages.DateTimePickerPage"> @@ -30,6 +31,16 @@ + + + + + + + + + A DatePicker with day formatted and year hidden. + + + + + + + + A TimePicker with a header and minute increments specified. diff --git a/samples/ControlCatalog/Pages/LabelsPage.axaml b/samples/ControlCatalog/Pages/LabelsPage.axaml new file mode 100644 index 0000000000..961e7ba7e6 --- /dev/null +++ b/samples/ControlCatalog/Pages/LabelsPage.axaml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/ControlCatalog/Pages/LabelsPage.axaml.cs b/samples/ControlCatalog/Pages/LabelsPage.axaml.cs new file mode 100644 index 0000000000..b8503d6ae6 --- /dev/null +++ b/samples/ControlCatalog/Pages/LabelsPage.axaml.cs @@ -0,0 +1,43 @@ +using Avalonia; +using Avalonia.Controls; +using Avalonia.Markup.Xaml; +using ControlCatalog.Models; +using ReactiveUI; + +namespace ControlCatalog.Pages +{ + public class LabelsPage : UserControl + { + private Person _person; + + public LabelsPage() + { + CreateDefaultPerson(); + this.InitializeComponent(); + } + + private void CreateDefaultPerson() + { + DataContext = _person = new Person + { + FirstName = "John", + LastName = "Doe", + IsBanned = true, + }; + } + + private void InitializeComponent() + { + AvaloniaXamlLoader.Load(this); + } + + public void DoSave() + { + + } + public void DoCancel() + { + CreateDefaultPerson(); + } + } +} diff --git a/samples/ControlCatalog/Pages/NumericUpDownPage.xaml b/samples/ControlCatalog/Pages/NumericUpDownPage.xaml index 0d7e5da17f..d75622f1fb 100644 --- a/samples/ControlCatalog/Pages/NumericUpDownPage.xaml +++ b/samples/ControlCatalog/Pages/NumericUpDownPage.xaml @@ -1,5 +1,6 @@  Numeric up-down control @@ -75,6 +76,15 @@ + + NumericUpDown with Validation Errors: + + + + + diff --git a/samples/ControlCatalog/Pages/RelativePanelPage.axaml b/samples/ControlCatalog/Pages/RelativePanelPage.axaml index 3657d52bd9..4dcdcc195f 100644 --- a/samples/ControlCatalog/Pages/RelativePanelPage.axaml +++ b/samples/ControlCatalog/Pages/RelativePanelPage.axaml @@ -23,16 +23,16 @@ - + - + - + @@ -41,19 +41,19 @@ - + - + - + - + - + diff --git a/samples/ControlCatalog/Pages/SliderPage.xaml b/samples/ControlCatalog/Pages/SliderPage.xaml index ea31ed0050..b3f32ed421 100644 --- a/samples/ControlCatalog/Pages/SliderPage.xaml +++ b/samples/ControlCatalog/Pages/SliderPage.xaml @@ -1,5 +1,6 @@ Slider @@ -21,6 +22,15 @@ IsSnapToTickEnabled="True" Ticks="0,20,25,40,75,100" Width="300" /> + + + + + + x:Class="ControlCatalog.Pages.TextBoxPage" + xmlns:sys="clr-namespace:System;assembly=netstandard"> - TextBox - A control into which the user can input text + + - + + + + + + + - + - - resm fonts - - - - - - - - res fonts - - - - - + + + + + + + + + + + + + + + diff --git a/samples/Previewer/App.xaml.cs b/samples/Previewer/App.xaml.cs index fffa987a27..ab83d45cd3 100644 --- a/samples/Previewer/App.xaml.cs +++ b/samples/Previewer/App.xaml.cs @@ -1,4 +1,5 @@ using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; namespace Previewer @@ -9,6 +10,13 @@ namespace Previewer { AvaloniaXamlLoader.Load(this); } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + desktop.MainWindow = new MainWindow(); + base.OnFrameworkInitializationCompleted(); + } } -} \ No newline at end of file +} diff --git a/samples/Previewer/Program.cs b/samples/Previewer/Program.cs index 48363e27f2..b12b93974a 100644 --- a/samples/Previewer/Program.cs +++ b/samples/Previewer/Program.cs @@ -1,13 +1,14 @@ -using System; -using Avalonia; +using Avalonia; namespace Previewer { class Program { - static void Main(string[] args) - { - AppBuilder.Configure().UsePlatformDetect().Start(); - } + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect(); + + public static int Main(string[] args) + => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); } -} \ No newline at end of file +} diff --git a/samples/RenderDemo/App.xaml.cs b/samples/RenderDemo/App.xaml.cs index 340ccdae19..e6ec963d75 100644 --- a/samples/RenderDemo/App.xaml.cs +++ b/samples/RenderDemo/App.xaml.cs @@ -1,4 +1,5 @@ using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; @@ -11,9 +12,17 @@ namespace RenderDemo AvaloniaXamlLoader.Load(this); } + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + desktop.MainWindow = new MainWindow(); + base.OnFrameworkInitializationCompleted(); + } + // TODO: Make this work with GTK/Skia/Cairo depending on command-line args // again. - static void Main(string[] args) => BuildAvaloniaApp().Start(); + static void Main(string[] args) + => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); // App configuration, used by the entry point and previewer static AppBuilder BuildAvaloniaApp() @@ -24,6 +33,6 @@ namespace RenderDemo }) .UsePlatformDetect() .UseReactiveUI() - .LogToDebug(); + .LogToTrace(); } } diff --git a/samples/RenderDemo/Pages/GlyphRunPage.xaml b/samples/RenderDemo/Pages/GlyphRunPage.xaml index fb3e318a0e..c2914e8847 100644 --- a/samples/RenderDemo/Pages/GlyphRunPage.xaml +++ b/samples/RenderDemo/Pages/GlyphRunPage.xaml @@ -6,9 +6,9 @@ x:Class="RenderDemo.Pages.GlyphRunPage"> - - + diff --git a/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs b/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs index ddee880288..857358f6b2 100644 --- a/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs +++ b/samples/RenderDemo/Pages/GlyphRunPage.xaml.cs @@ -9,7 +9,7 @@ namespace RenderDemo.Pages { public class GlyphRunPage : UserControl { - private DrawingPresenter _drawingPresenter; + private Image _imageControl; private GlyphTypeface _glyphTypeface = Typeface.Default.GlyphTypeface; private readonly Random _rand = new Random(); private ushort[] _glyphIndices = new ushort[1]; @@ -25,7 +25,8 @@ namespace RenderDemo.Pages { AvaloniaXamlLoader.Load(this); - _drawingPresenter = this.FindControl("drawingPresenter"); + _imageControl = this.FindControl("imageControl"); + _imageControl.Source = new DrawingImage(); DispatcherTimer.Run(() => { @@ -73,7 +74,7 @@ namespace RenderDemo.Pages drawingGroup.Children.Add(geometryDrawing); - _drawingPresenter.Drawing = drawingGroup; + (_imageControl.Source as DrawingImage).Drawing = drawingGroup; } } } diff --git a/samples/Sandbox/Program.cs b/samples/Sandbox/Program.cs index 4d7eda8d9f..7d41a8b8c0 100644 --- a/samples/Sandbox/Program.cs +++ b/samples/Sandbox/Program.cs @@ -10,7 +10,7 @@ namespace Sandbox AppBuilder.Configure() .UsePlatformDetect() .UseReactiveUI() - .LogToDebug() + .LogToTrace() .StartWithClassicDesktopLifetime(args); } } diff --git a/samples/VirtualizationDemo/App.xaml.cs b/samples/VirtualizationDemo/App.xaml.cs index 5990dd282c..81b80c1f40 100644 --- a/samples/VirtualizationDemo/App.xaml.cs +++ b/samples/VirtualizationDemo/App.xaml.cs @@ -1,4 +1,5 @@ using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; namespace VirtualizationDemo @@ -9,5 +10,12 @@ namespace VirtualizationDemo { AvaloniaXamlLoader.Load(this); } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + desktop.MainWindow = new MainWindow(); + base.OnFrameworkInitializationCompleted(); + } } } diff --git a/samples/VirtualizationDemo/Program.cs b/samples/VirtualizationDemo/Program.cs index 93ea5e1b88..46c05f74b2 100644 --- a/samples/VirtualizationDemo/Program.cs +++ b/samples/VirtualizationDemo/Program.cs @@ -1,19 +1,17 @@ -using System; -using Avalonia; -using Avalonia.Controls; +using Avalonia; using Avalonia.ReactiveUI; namespace VirtualizationDemo { class Program { - static void Main(string[] args) - { - AppBuilder.Configure() - .UsePlatformDetect() - .UseReactiveUI() - .LogToDebug() - .Start(); - } + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .UsePlatformDetect() + .UseReactiveUI() + .LogToTrace(); + + public static int Main(string[] args) + => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); } } diff --git a/samples/interop/Direct3DInteropSample/App.paml.cs b/samples/interop/Direct3DInteropSample/App.paml.cs index 1b6d5fd39c..29365decfe 100644 --- a/samples/interop/Direct3DInteropSample/App.paml.cs +++ b/samples/interop/Direct3DInteropSample/App.paml.cs @@ -1,4 +1,5 @@ using Avalonia; +using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Markup.Xaml; namespace Direct3DInteropSample @@ -9,5 +10,12 @@ namespace Direct3DInteropSample { AvaloniaXamlLoader.Load(this); } + + public override void OnFrameworkInitializationCompleted() + { + if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) + desktop.MainWindow = new MainWindow(); + base.OnFrameworkInitializationCompleted(); + } } } diff --git a/samples/interop/Direct3DInteropSample/Program.cs b/samples/interop/Direct3DInteropSample/Program.cs index 21302fa68a..bf8e76d7e4 100644 --- a/samples/interop/Direct3DInteropSample/Program.cs +++ b/samples/interop/Direct3DInteropSample/Program.cs @@ -1,19 +1,16 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using Avalonia; +using Avalonia; namespace Direct3DInteropSample { class Program { - static void Main(string[] args) - { - AppBuilder.Configure() - .With(new Win32PlatformOptions {UseDeferredRendering = false}) - .UseWin32().UseDirect2D1().Start(); - } + public static AppBuilder BuildAvaloniaApp() + => AppBuilder.Configure() + .With(new Win32PlatformOptions { UseDeferredRendering = false }) + .UseWin32() + .UseDirect2D1(); + + public static int Main(string[] args) + => BuildAvaloniaApp().StartWithClassicDesktopLifetime(args); } } diff --git a/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj b/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj index cc831ef8ae..c25442b52c 100644 --- a/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj +++ b/samples/interop/NativeEmbedSample/NativeEmbedSample.csproj @@ -9,11 +9,10 @@ - - + Designer diff --git a/src/Avalonia.Animation/Properties/AssemblyInfo.cs b/src/Avalonia.Animation/Properties/AssemblyInfo.cs index d34fd06272..221b51e95a 100644 --- a/src/Avalonia.Animation/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Animation/Properties/AssemblyInfo.cs @@ -6,5 +6,10 @@ using System.Runtime.CompilerServices; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Easings")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Animation.Animators")] +#if SIGNED_BUILD +[assembly: InternalsVisibleTo("Avalonia.LeakTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] +[assembly: InternalsVisibleTo("Avalonia.Animation.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] +#else [assembly: InternalsVisibleTo("Avalonia.LeakTests")] [assembly: InternalsVisibleTo("Avalonia.Animation.UnitTests")] +#endif diff --git a/src/Avalonia.Base/ApiCompatBaseline.txt b/src/Avalonia.Base/ApiCompatBaseline.txt index 4668a572c5..5d19373a92 100644 --- a/src/Avalonia.Base/ApiCompatBaseline.txt +++ b/src/Avalonia.Base/ApiCompatBaseline.txt @@ -1,3 +1,4 @@ Compat issues with assembly Avalonia.Base: CannotAddAbstractMembers : Member 'protected System.IObservable Avalonia.AvaloniaProperty.GetChanged()' is abstract in the implementation but is missing in the contract. -Total Issues: 1 +TypesMustExist : Type 'Avalonia.Logging.DebugLogSink' does not exist in the implementation but it does exist in the contract. +Total Issues: 2 diff --git a/src/Avalonia.Base/Logging/DebugLogSink.cs b/src/Avalonia.Base/Logging/TraceLogSink.cs similarity index 92% rename from src/Avalonia.Base/Logging/DebugLogSink.cs rename to src/Avalonia.Base/Logging/TraceLogSink.cs index 3695afa860..f597844378 100644 --- a/src/Avalonia.Base/Logging/DebugLogSink.cs +++ b/src/Avalonia.Base/Logging/TraceLogSink.cs @@ -6,12 +6,12 @@ using Avalonia.Utilities; namespace Avalonia.Logging { - public class DebugLogSink : ILogSink + public class TraceLogSink : ILogSink { private readonly LogEventLevel _level; private readonly IList _areas; - public DebugLogSink( + public TraceLogSink( LogEventLevel minimumLevel, IList areas = null) { @@ -28,7 +28,7 @@ namespace Avalonia.Logging { if (IsEnabled(level, area)) { - Debug.WriteLine(Format(area, messageTemplate, source)); + Trace.WriteLine(Format(area, messageTemplate, source)); } } @@ -36,7 +36,7 @@ namespace Avalonia.Logging { if (IsEnabled(level, area)) { - Debug.WriteLine(Format(area, messageTemplate, source, propertyValue0)); + Trace.WriteLine(Format(area, messageTemplate, source, propertyValue0)); } } @@ -44,7 +44,7 @@ namespace Avalonia.Logging { if (IsEnabled(level, area)) { - Debug.WriteLine(Format(area, messageTemplate, source, propertyValue0, propertyValue1)); + Trace.WriteLine(Format(area, messageTemplate, source, propertyValue0, propertyValue1)); } } @@ -52,7 +52,7 @@ namespace Avalonia.Logging { if (IsEnabled(level, area)) { - Debug.WriteLine(Format(area, messageTemplate, source, propertyValue0, propertyValue1, propertyValue2)); + Trace.WriteLine(Format(area, messageTemplate, source, propertyValue0, propertyValue1, propertyValue2)); } } @@ -60,7 +60,7 @@ namespace Avalonia.Logging { if (IsEnabled(level, area)) { - Debug.WriteLine(Format(area, messageTemplate, source, propertyValues)); + Trace.WriteLine(Format(area, messageTemplate, source, propertyValues)); } } diff --git a/src/Avalonia.Base/Metadata/XmlnsPrefixAttribute.cs b/src/Avalonia.Base/Metadata/XmlnsPrefixAttribute.cs new file mode 100644 index 0000000000..ad017822e4 --- /dev/null +++ b/src/Avalonia.Base/Metadata/XmlnsPrefixAttribute.cs @@ -0,0 +1,39 @@ +using System; + +namespace Avalonia.Metadata +{ + /// + /// Use to predefine the prefix associated to an xml namespace in a xaml file + /// + /// + /// example: + /// [assembly: XmlnsPrefix("https://github.com/avaloniaui", "av")] + /// xaml: + /// xmlns:av="https://github.com/avaloniaui" + /// + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] + public sealed class XmlnsPrefixAttribute : Attribute + { + /// + /// Constructor + /// + /// XML namespce + /// recommended prefix + public XmlnsPrefixAttribute(string xmlNamespace, string prefix) + { + XmlNamespace = xmlNamespace ?? throw new ArgumentNullException(nameof(xmlNamespace)); + + Prefix = prefix ?? throw new ArgumentNullException(nameof(prefix)); + } + + /// + /// XML Namespace + /// + public string XmlNamespace { get; } + + /// + /// New Xml Namespace + /// + public string Prefix { get; } + } +} diff --git a/src/Avalonia.Base/Properties/AssemblyInfo.cs b/src/Avalonia.Base/Properties/AssemblyInfo.cs index 13b247de51..e06cb75a4d 100644 --- a/src/Avalonia.Base/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Base/Properties/AssemblyInfo.cs @@ -5,8 +5,16 @@ using System.Runtime.CompilerServices; using Avalonia.Metadata; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Data.Converters")] +#if SIGNED_BUILD +[assembly: InternalsVisibleTo("Avalonia.Base.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] +[assembly: InternalsVisibleTo("Avalonia.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] +[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")] +[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] +[assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] +#else [assembly: InternalsVisibleTo("Avalonia.Base.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.UnitTests")] [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")] [assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid")] [assembly: InternalsVisibleTo("Avalonia.Markup.Xaml.UnitTests")] +#endif diff --git a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj index 490364c0d8..94ad4adb7d 100644 --- a/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj +++ b/src/Avalonia.Build.Tasks/Avalonia.Build.Tasks.csproj @@ -59,7 +59,7 @@ - + diff --git a/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs b/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs index 95e59dde2b..8e1f6c257d 100644 --- a/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs +++ b/src/Avalonia.Build.Tasks/CompileAvaloniaXamlTask.cs @@ -39,7 +39,9 @@ namespace Avalonia.Build.Tasks var res = XamlCompilerTaskExecutor.Compile(BuildEngine, input, File.ReadAllLines(ReferencesFilePath).Where(l => !string.IsNullOrWhiteSpace(l)).ToArray(), - ProjectDirectory, OutputPath, VerifyIl, outputImportance); + ProjectDirectory, OutputPath, VerifyIl, outputImportance, + (SignAssembly && !DelaySign) ? AssemblyOriginatorKeyFile : null + ); if (!res.Success) return false; if (!res.WrittenFile) @@ -73,6 +75,10 @@ namespace Avalonia.Build.Tasks public string OutputPath { get; set; } public bool VerifyIl { get; set; } + + public string AssemblyOriginatorKeyFile { get; set; } + public bool SignAssembly { get; set; } + public bool DelaySign { get; set; } public string ReportImportance { get; set; } diff --git a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs index c9c9c562bd..6b01af2ede 100644 --- a/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs +++ b/src/Avalonia.Build.Tasks/XamlCompilerTaskExecutor.cs @@ -42,7 +42,7 @@ namespace Avalonia.Build.Tasks } public static CompileResult Compile(IBuildEngine engine, string input, string[] references, string projectDirectory, - string output, bool verifyIl, MessageImportance logImportance) + string output, bool verifyIl, MessageImportance logImportance, string strongNameKey) { var typeSystem = new CecilTypeSystem(references.Concat(new[] {input}), input); var asm = typeSystem.TargetAssemblyDefinition; @@ -345,6 +345,20 @@ namespace Avalonia.Build.Tasks } res.Remove(); } + + + // Technically that's a hack, but it fixes corert incompatibility caused by deterministic builds + int dupeCounter = 1; + foreach (var grp in typeDef.NestedTypes.GroupBy(x => x.Name)) + { + if (grp.Count() > 1) + { + foreach (var dupe in grp) + dupe.Name += "_dup" + dupeCounter++; + } + } + + return true; } @@ -361,10 +375,12 @@ namespace Avalonia.Build.Tasks loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ldnull)); loaderDispatcherMethod.Body.Instructions.Add(Instruction.Create(OpCodes.Ret)); - asm.Write(output, new WriterParameters - { - WriteSymbols = asm.MainModule.HasSymbols - }); + + var writerParameters = new WriterParameters { WriteSymbols = asm.MainModule.HasSymbols }; + if (!string.IsNullOrWhiteSpace(strongNameKey)) + writerParameters.StrongNameKeyBlob = File.ReadAllBytes(strongNameKey); + + asm.Write(output, writerParameters); return new CompileResult(true, true); } diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs index 23c4acdf6c..92ddd4e736 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumn.cs @@ -665,6 +665,7 @@ namespace Avalonia.Controls /// /// The data item represented by the row that contains the intended cell. /// + /// When the method returns, contains the applied binding. /// /// A new editing element that is bound to the column's property value. /// diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs index 856d1f6566..7f8d205949 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumnHeader.cs @@ -340,8 +340,6 @@ namespace Avalonia.Controls if (OwningGrid != null && OwningGrid.ColumnHeaders != null) { - args.Pointer.Capture(this); - _dragMode = DragMode.MouseDown; _frozenColumnsWidth = OwningGrid.ColumnsInternal.GetVisibleFrozenEdgedColumnsWidth(); _lastMousePositionHeaders = this.Translate(OwningGrid.ColumnHeaders, mousePosition); @@ -413,8 +411,9 @@ namespace Avalonia.Controls } //TODO DragEvents - internal void OnMouseMove(ref bool handled, Point mousePosition, Point mousePositionHeaders) + internal void OnMouseMove(PointerEventArgs args, Point mousePosition, Point mousePositionHeaders) { + var handled = args.Handled; if (handled || OwningGrid == null || OwningGrid.ColumnHeaders == null) { return; @@ -438,7 +437,10 @@ namespace Avalonia.Controls } _lastMousePositionHeaders = mousePositionHeaders; - + + if (args.Pointer.Captured != this && _dragMode == DragMode.Drag) + args.Pointer.Capture(this); + SetDragCursor(mousePosition); } @@ -506,8 +508,7 @@ namespace Avalonia.Controls Point mousePosition = e.GetPosition(this); Point mousePositionHeaders = e.GetPosition(OwningGrid.ColumnHeaders); - bool handled = false; - OnMouseMove(ref handled, mousePosition, mousePositionHeaders); + OnMouseMove(e, mousePosition, mousePositionHeaders); } /// diff --git a/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs b/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs index 82b01e99bb..1b122996d2 100644 --- a/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Controls.DataGrid/Properties/AssemblyInfo.cs @@ -1,10 +1,13 @@ using System.Reflection; using System.Runtime.CompilerServices; using Avalonia.Metadata; - +#if SIGNED_BUILD +[assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] +[assembly: InternalsVisibleTo("Avalonia.DesignerSupport, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] +#else [assembly: InternalsVisibleTo("Avalonia.Controls.DataGrid.UnitTests")] [assembly: InternalsVisibleTo("Avalonia.DesignerSupport")] - +#endif [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Collections")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls.Primitives")] diff --git a/src/Avalonia.Controls/ApiCompatBaseline.txt b/src/Avalonia.Controls/ApiCompatBaseline.txt index af88c569a6..16c801201c 100644 --- a/src/Avalonia.Controls/ApiCompatBaseline.txt +++ b/src/Avalonia.Controls/ApiCompatBaseline.txt @@ -8,6 +8,12 @@ MembersMustExist : Member 'public void Avalonia.Controls.ListBox.Selection.set(A TypesMustExist : Type 'Avalonia.Controls.SelectionModel' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'Avalonia.Controls.SelectionModelChildrenRequestedEventArgs' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'Avalonia.Controls.SelectionModelSelectionChangedEventArgs' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.SplitView.ContentProperty' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public Avalonia.StyledProperty Avalonia.StyledProperty Avalonia.Controls.SplitView.PaneProperty' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public Avalonia.Controls.IControl Avalonia.Controls.SplitView.Content.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void Avalonia.Controls.SplitView.Content.set(Avalonia.Controls.IControl)' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public Avalonia.Controls.IControl Avalonia.Controls.SplitView.Pane.get()' does not exist in the implementation but it does exist in the contract. +MembersMustExist : Member 'public void Avalonia.Controls.SplitView.Pane.set(Avalonia.Controls.IControl)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.DirectProperty Avalonia.DirectProperty Avalonia.Controls.TreeView.SelectionProperty' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Controls.TreeView.SelectionChangedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Controls.ISelectionModel Avalonia.Controls.TreeView.Selection.get()' does not exist in the implementation but it does exist in the contract. @@ -17,4 +23,4 @@ InterfacesShouldHaveSameMembers : Interface member 'public System.String[] Avalo MembersMustExist : Member 'public Avalonia.DirectProperty Avalonia.DirectProperty Avalonia.Controls.Primitives.SelectingItemsControl.SelectionProperty' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'protected Avalonia.Controls.ISelectionModel Avalonia.Controls.Primitives.SelectingItemsControl.Selection.get()' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'protected void Avalonia.Controls.Primitives.SelectingItemsControl.Selection.set(Avalonia.Controls.ISelectionModel)' does not exist in the implementation but it does exist in the contract. -Total Issues: 18 +Total Issues: 24 diff --git a/src/Avalonia.Controls/ContextMenu.cs b/src/Avalonia.Controls/ContextMenu.cs index c4df5c1815..ec9649bc64 100644 --- a/src/Avalonia.Controls/ContextMenu.cs +++ b/src/Avalonia.Controls/ContextMenu.cs @@ -62,6 +62,12 @@ namespace Avalonia.Controls public static readonly StyledProperty PlacementRectProperty = AvaloniaProperty.Register(nameof(PlacementRect)); + /// + /// Defines the property. + /// + public static readonly StyledProperty WindowManagerAddShadowHintProperty = + Popup.WindowManagerAddShadowHintProperty.AddOwner(); + /// /// Defines the property. /// @@ -158,6 +164,12 @@ namespace Avalonia.Controls set { SetValue(PlacementModeProperty, value); } } + public bool WindowManagerAddShadowHint + { + get { return GetValue(WindowManagerAddShadowHintProperty); } + set { SetValue(WindowManagerAddShadowHintProperty, value); } + } + /// /// Gets or sets the the anchor rectangle within the parent that the context menu will be placed /// relative to when is . @@ -267,6 +279,7 @@ namespace Avalonia.Controls PlacementTarget = PlacementTarget ?? control, IsLightDismissEnabled = true, OverlayDismissEventPassThrough = true, + WindowManagerAddShadowHint = WindowManagerAddShadowHint, }; _popup.Opened += PopupOpened; diff --git a/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs b/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs index daee7968eb..a0e8c03195 100644 --- a/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs +++ b/src/Avalonia.Controls/DateTimePickers/DateTimePickerPanel.cs @@ -486,9 +486,9 @@ namespace Avalonia.Controls.Primitives switch (panelType) { case DateTimePickerPanelType.Year: - return new DateTime(value, FormatDate.Month, FormatDate.Day).ToString(ItemFormat); + return new DateTime(value, 1, 1).ToString(ItemFormat); case DateTimePickerPanelType.Month: - return new DateTime(FormatDate.Year, value, FormatDate.Day).ToString(ItemFormat); + return new DateTime(FormatDate.Year, value, 1).ToString(ItemFormat); case DateTimePickerPanelType.Day: return new DateTime(FormatDate.Year, FormatDate.Month, value).ToString(ItemFormat); case DateTimePickerPanelType.Hour: diff --git a/src/Avalonia.Controls/ItemsControl.cs b/src/Avalonia.Controls/ItemsControl.cs index 3aec06e4eb..4dc8aec6f3 100644 --- a/src/Avalonia.Controls/ItemsControl.cs +++ b/src/Avalonia.Controls/ItemsControl.cs @@ -169,7 +169,7 @@ namespace Avalonia.Controls /// /// The collection. /// The index. - /// The index of the item or -1 if the item was not found. + /// The item at the given index or null if the index is out of bounds. protected static object ElementAt(IEnumerable items, int index) { if (index != -1 && index < items.Count()) diff --git a/src/Avalonia.Controls/Label.cs b/src/Avalonia.Controls/Label.cs new file mode 100644 index 0000000000..9d5eda464f --- /dev/null +++ b/src/Avalonia.Controls/Label.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Text; +using Avalonia.Controls.Primitives; +using Avalonia.Controls.Templates; +using Avalonia.Data; +using Avalonia.Input; +using Avalonia.Interactivity; + +namespace Avalonia.Controls +{ + /// + /// Label control. Focuses on pointer click or access key press (Alt + accessKey) + /// + public class Label : ContentControl + { + /// + /// Defines the Direct property + /// + public static readonly DirectProperty TargetProperty = + AvaloniaProperty.RegisterDirect(nameof(Target), lbl => lbl.Target, (lbl, inp) => lbl.Target = inp); + + /// + /// Label focus target storage field + /// + private IInputElement _target; + + /// + /// Label focus Target + /// + [ResolveByName] + public IInputElement Target + { + get => _target; + set => SetAndRaise(TargetProperty, ref _target, value); + } + + static Label() + { + AccessKeyHandler.AccessKeyPressedEvent.AddClassHandler /// The object to which the property value is written. /// The value to set. (The element to align this element's bottom edge with.) + [ResolveByName] public static void SetAlignBottomWith(AvaloniaObject obj, object value) { obj.SetValue(AlignBottomWithProperty, value); @@ -185,6 +187,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to align this element's horizontal center with.) + [ResolveByName] public static void SetAlignHorizontalCenterWith(AvaloniaObject obj, object value) { obj.SetValue(AlignHorizontalCenterWithProperty, value); @@ -250,6 +253,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to align this element's left edge with.) + [ResolveByName] public static void SetAlignLeftWith(AvaloniaObject obj, object value) { obj.SetValue(AlignLeftWithProperty, value); @@ -315,6 +319,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to align this element's right edge with.) + [ResolveByName] public static void SetAlignRightWith(AvaloniaObject obj, object value) { obj.SetValue(AlignRightWithProperty, value); @@ -376,6 +381,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to align this element's top edge with.) + [ResolveByName] public static void SetAlignTopWith(AvaloniaObject obj, object value) { obj.SetValue(AlignTopWithProperty, value); @@ -437,7 +443,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to align this element's horizontal center with.) - + [ResolveByName] public static void SetAlignVerticalCenterWith(AvaloniaObject obj, object value) { obj.SetValue(AlignVerticalCenterWithProperty, value); @@ -468,7 +474,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to position this element below.) - + [ResolveByName] public static void SetBelow(AvaloniaObject obj, object value) { obj.SetValue(BelowProperty, value); @@ -500,6 +506,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to position this element to the left of.) + [ResolveByName] public static void SetLeftOf(AvaloniaObject obj, object value) { obj.SetValue(LeftOfProperty, value); @@ -531,6 +538,7 @@ namespace Avalonia.Controls /// /// The object to which the property value is written. /// The value to set. (The element to position this element to the right of.) + [ResolveByName] public static void SetRightOf(AvaloniaObject obj, object value) { obj.SetValue(RightOfProperty, value); diff --git a/src/Avalonia.Controls/ResolveByNameAttribute.cs b/src/Avalonia.Controls/ResolveByNameAttribute.cs index a00e3f8a1b..a13b10d630 100644 --- a/src/Avalonia.Controls/ResolveByNameAttribute.cs +++ b/src/Avalonia.Controls/ResolveByNameAttribute.cs @@ -2,8 +2,12 @@ namespace Avalonia.Controls { + /// + /// Indicates that the property resolves an element by Name or x:Name. + /// When applying this to attached properties, ensure to put on both + /// the Getter and Setter methods. + /// public class ResolveByNameAttribute : Attribute { - } } diff --git a/src/Avalonia.Controls/Selection/SelectionModel.cs b/src/Avalonia.Controls/Selection/SelectionModel.cs index 3b5d57a7b8..054974e4f1 100644 --- a/src/Avalonia.Controls/Selection/SelectionModel.cs +++ b/src/Avalonia.Controls/Selection/SelectionModel.cs @@ -442,7 +442,8 @@ namespace Avalonia.Controls.Selection RaisePropertyChanged(nameof(SelectedIndex)); } - if (e.Action == NotifyCollectionChangedAction.Remove && e.OldStartingIndex <= oldSelectedIndex) + if ((e.Action == NotifyCollectionChangedAction.Remove && e.OldStartingIndex <= oldSelectedIndex) || + e.Action == NotifyCollectionChangedAction.Reset) { RaisePropertyChanged(nameof(SelectedItem)); } diff --git a/src/Avalonia.Controls/SplitView.cs b/src/Avalonia.Controls/SplitView.cs index 8267efc466..4500d52484 100644 --- a/src/Avalonia.Controls/SplitView.cs +++ b/src/Avalonia.Controls/SplitView.cs @@ -9,6 +9,8 @@ using Avalonia.Platform; using Avalonia.VisualTree; using System; using System.Reactive.Disposables; +using Avalonia.Controls.Presenters; +using Avalonia.Controls.Templates; namespace Avalonia.Controls { @@ -78,7 +80,7 @@ namespace Avalonia.Controls [PseudoClasses(":compactoverlay", ":compactinline", ":overlay", ":inline")] [PseudoClasses(":left", ":right")] [PseudoClasses(":lightdismiss")] - public class SplitView : TemplatedControl + public class SplitView : ContentControl { /* Pseudo classes & combos @@ -87,12 +89,6 @@ namespace Avalonia.Controls :left :right */ - /// - /// Defines the property - /// - public static readonly StyledProperty ContentProperty = - AvaloniaProperty.Register(nameof(Content)); - /// /// Defines the property /// @@ -133,8 +129,14 @@ namespace Avalonia.Controls /// /// Defines the property /// - public static readonly StyledProperty PaneProperty = - AvaloniaProperty.Register(nameof(Pane)); + public static readonly StyledProperty PaneProperty = + AvaloniaProperty.Register(nameof(Pane)); + + /// + /// Defines the property. + /// + public static readonly StyledProperty PaneTemplateProperty = + AvaloniaProperty.Register(nameof(PaneTemplate)); /// /// Defines the property @@ -166,16 +168,7 @@ namespace Avalonia.Controls CompactPaneLengthProperty.Changed.AddClassHandler((x, v) => x.OnCompactPaneLengthChanged(v)); PanePlacementProperty.Changed.AddClassHandler((x, v) => x.OnPanePlacementChanged(v)); DisplayModeProperty.Changed.AddClassHandler((x, v) => x.OnDisplayModeChanged(v)); - } - - /// - /// Gets or sets the content of the SplitView - /// - [Content] - public IControl Content - { - get => GetValue(ContentProperty); - set => SetValue(ContentProperty, value); + } /// @@ -265,11 +258,20 @@ namespace Avalonia.Controls /// /// Gets or sets the Pane for the SplitView /// - public IControl Pane + public object Pane { get => GetValue(PaneProperty); set => SetValue(PaneProperty, value); } + + /// + /// Gets or sets the data template used to display the header content of the control. + /// + public IDataTemplate? PaneTemplate + { + get => GetValue(PaneTemplateProperty); + set => SetValue(PaneTemplateProperty, value); + } /// /// Gets or sets whether WinUI equivalent LightDismissOverlayMode is enabled @@ -312,6 +314,18 @@ namespace Avalonia.Controls /// public event EventHandler PaneOpening; + protected override bool RegisterContentPresenter(IContentPresenter presenter) + { + var result = base.RegisterContentPresenter(presenter); + + if (presenter.Name == "PART_PanePresenter") + { + return true; + } + + return result; + } + protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); diff --git a/src/Avalonia.Controls/Templates/FuncDataTemplate.cs b/src/Avalonia.Controls/Templates/FuncDataTemplate.cs index 1afd86a11e..5dff13997e 100644 --- a/src/Avalonia.Controls/Templates/FuncDataTemplate.cs +++ b/src/Avalonia.Controls/Templates/FuncDataTemplate.cs @@ -1,5 +1,6 @@ using System; using System.Reactive.Linq; +using Avalonia.Controls.Primitives; namespace Avalonia.Controls.Templates { @@ -30,6 +31,31 @@ namespace Avalonia.Controls.Templates }, true); + /// + /// The default data template used in the case where no matching data template is found + /// but should be used. + /// + public static readonly FuncDataTemplate Access = + new FuncDataTemplate( + (data, s) => + { + if (data != null) + { + var result = new AccessText(); + result.Bind(TextBlock.TextProperty, + result.GetObservable(Control.DataContextProperty).Select(x => x?.ToString())); + return result; + } + else + { + return null; + } + }, + true); + + /// + /// The implementation of the method. + /// private readonly Func _match; private readonly bool _supportsRecycling; @@ -42,7 +68,7 @@ namespace Avalonia.Controls.Templates /// /// Whether the control can be recycled. public FuncDataTemplate( - Type type, + Type type, Func build, bool supportsRecycling = false) : this(o => IsInstance(o, type), build, supportsRecycling) diff --git a/src/Avalonia.Controls/TextBlock.cs b/src/Avalonia.Controls/TextBlock.cs index d61519e697..31517ba59d 100644 --- a/src/Avalonia.Controls/TextBlock.cs +++ b/src/Avalonia.Controls/TextBlock.cs @@ -3,6 +3,7 @@ using Avalonia.LogicalTree; using Avalonia.Media; using Avalonia.Media.TextFormatting; using Avalonia.Metadata; +using Avalonia.Layout; namespace Avalonia.Controls { @@ -427,14 +428,32 @@ namespace Avalonia.Controls case TextAlignment.Center: offsetX = (width - TextLayout.Size.Width) / 2; break; + case TextAlignment.Right: - offsetX = width - TextLayout.Size.Width; + offsetX = width - TextLayout.Size.Width; break; } var padding = Padding; - using (context.PushPostTransform(Matrix.CreateTranslation(padding.Left + offsetX, padding.Top))) + var top = padding.Top; + var textSize = TextLayout.Size; + + if (Bounds.Height < textSize.Height) + { + switch (VerticalAlignment) + { + case VerticalAlignment.Center: + top += (Bounds.Height - textSize.Height) / 2; + break; + + case VerticalAlignment.Bottom: + top += (Bounds.Height - textSize.Height); + break; + } + } + + using (context.PushPostTransform(Matrix.CreateTranslation(padding.Left + offsetX, top))) { TextLayout.Draw(context); } diff --git a/src/Avalonia.Controls/Window.cs b/src/Avalonia.Controls/Window.cs index 317b6d3f2e..54574a7e1c 100644 --- a/src/Avalonia.Controls/Window.cs +++ b/src/Avalonia.Controls/Window.cs @@ -451,7 +451,7 @@ namespace Avalonia.Controls /// /// The dialog result. /// - /// When the window is shown with the + /// When the window is shown with the /// or method, the /// resulting task will produce the value when the window /// is closed. diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs index d9a0d17518..9363c28705 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreeNode.cs @@ -23,6 +23,8 @@ namespace Avalonia.Diagnostics.ViewModels if (visual is IControl control) { + ElementName = control.Name; + var removed = Observable.FromEventPattern( x => control.DetachedFromLogicalTree += x, x => control.DetachedFromLogicalTree -= x); @@ -61,6 +63,11 @@ namespace Avalonia.Diagnostics.ViewModels private set { RaiseAndSetIfChanged(ref _classes, value); } } + public string ElementName + { + get; + } + public IVisual Visual { get; diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml index b2d3a8bddb..8aad5fffd8 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml @@ -26,6 +26,12 @@ + + + + diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs index 10861538ae..c4f9185728 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainWindow.xaml.cs @@ -76,7 +76,13 @@ namespace Avalonia.Diagnostics.Views if (e.Modifiers == modifiers) { var point = (Root as IInputRoot)?.MouseDevice?.GetPosition(Root) ?? default; - var control = Root.GetVisualsAt(point, x => (!(x is AdornerLayer) && x.IsVisible)) + + var control = Root.GetVisualsAt(point, x => + { + if (x is AdornerLayer || !x.IsVisible) return false; + if (!(x is IInputElement ie)) return true; + return ie.IsHitTestVisible; + }) .FirstOrDefault(); if (control != null) diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml index a1e6ca7d37..98de9b611e 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/TreePageView.xaml @@ -2,7 +2,7 @@ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:Avalonia.Diagnostics.ViewModels" x:Class="Avalonia.Diagnostics.Views.TreePageView"> - + + diff --git a/src/Avalonia.Dialogs/ApiCompatBaseline.txt b/src/Avalonia.Dialogs/ApiCompatBaseline.txt new file mode 100644 index 0000000000..fcc74cf864 --- /dev/null +++ b/src/Avalonia.Dialogs/ApiCompatBaseline.txt @@ -0,0 +1 @@ +Total Issues: 0 diff --git a/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj b/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj index 260d7350d2..81af76dc20 100644 --- a/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj +++ b/src/Avalonia.FreeDesktop/Avalonia.FreeDesktop.csproj @@ -6,9 +6,7 @@ + - - - diff --git a/src/Avalonia.Input/MouseDevice.cs b/src/Avalonia.Input/MouseDevice.cs index cec5029c18..5c63546f5d 100644 --- a/src/Avalonia.Input/MouseDevice.cs +++ b/src/Avalonia.Input/MouseDevice.cs @@ -19,6 +19,7 @@ namespace Avalonia.Input private readonly Pointer _pointer; private bool _disposed; + private PixelPoint? _position; public MouseDevice(Pointer? pointer = null) { @@ -39,10 +40,11 @@ namespace Avalonia.Input /// /// Gets the mouse position, in screen coordinates. /// + [Obsolete("Use events instead")] public PixelPoint Position { - get; - protected set; + get => _position ?? new PixelPoint(-1, -1); + protected set => _position = value; } /// @@ -91,7 +93,16 @@ namespace Avalonia.Input public void SceneInvalidated(IInputRoot root, Rect rect) { - var clientPoint = root.PointToClient(Position); + // Pointer is outside of the target area + if (_position == null ) + { + if (root.PointerOverElement != null) + ClearPointerOver(this, 0, root, PointerPointProperties.None, KeyModifiers.None); + return; + } + + + var clientPoint = root.PointToClient(_position.Value); if (rect.Contains(clientPoint)) { @@ -132,7 +143,7 @@ namespace Avalonia.Input if(mouse._disposed) return; - Position = e.Root.PointToScreen(e.Position); + _position = e.Root.PointToScreen(e.Position); var props = CreateProperties(e); var keyModifiers = KeyModifiersUtils.ConvertToKey(e.InputModifiers); switch (e.Type) @@ -176,6 +187,7 @@ namespace Avalonia.Input device = device ?? throw new ArgumentNullException(nameof(device)); root = root ?? throw new ArgumentNullException(nameof(root)); + _position = null; ClearPointerOver(this, timestamp, root, properties, inputModifiers); } diff --git a/src/Avalonia.Layout/Properties/AssemblyInfo.cs b/src/Avalonia.Layout/Properties/AssemblyInfo.cs index 0a6a32493a..63afaa8e3e 100644 --- a/src/Avalonia.Layout/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Layout/Properties/AssemblyInfo.cs @@ -1,7 +1,9 @@ using System.Runtime.CompilerServices; using Avalonia.Metadata; - +#if SIGNED_BUILD +[assembly: InternalsVisibleTo("Avalonia.Layout.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] +#else [assembly: InternalsVisibleTo("Avalonia.Layout.UnitTests")] - +#endif [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Layout")] diff --git a/src/Avalonia.Native/WindowImplBase.cs b/src/Avalonia.Native/WindowImplBase.cs index 5d35c773d7..0ecf8f856a 100644 --- a/src/Avalonia.Native/WindowImplBase.cs +++ b/src/Avalonia.Native/WindowImplBase.cs @@ -251,6 +251,9 @@ namespace Avalonia.Native public bool RawTextInputEvent(uint timeStamp, string text) { + if (_inputRoot is null) + return false; + Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); var args = new RawTextInputEventArgs(_keyboard, timeStamp, _inputRoot, text); @@ -262,6 +265,9 @@ namespace Avalonia.Native public bool RawKeyEvent(AvnRawKeyEventType type, uint timeStamp, AvnInputModifiers modifiers, uint key) { + if (_inputRoot is null) + return false; + Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); var args = new RawKeyEventArgs(_keyboard, timeStamp, _inputRoot, (RawKeyEventType)type, (Key)key, (RawInputModifiers)modifiers); @@ -278,6 +284,9 @@ namespace Avalonia.Native public void RawMouseEvent(AvnRawMouseEventType type, uint timeStamp, AvnInputModifiers modifiers, AvnPoint point, AvnVector delta) { + if (_inputRoot is null) + return; + Dispatcher.UIThread.RunJobs(DispatcherPriority.Input + 1); switch (type) @@ -332,8 +341,7 @@ namespace Avalonia.Native public void Invalidate(Rect rect) { - if (!_deferredRendering && _native != null) - _native.Invalidate(new AvnRect { Height = rect.Height, Width = rect.Width, X = rect.X, Y = rect.Y }); + _native?.Invalidate(new AvnRect { Height = rect.Height, Width = rect.Width, X = rect.X, Y = rect.Y }); } public void SetInputRoot(IInputRoot inputRoot) diff --git a/src/Avalonia.OpenGL/Angle/AngleEglInterface.cs b/src/Avalonia.OpenGL/Angle/AngleEglInterface.cs index 8c9b028164..3a332f37ad 100644 --- a/src/Avalonia.OpenGL/Angle/AngleEglInterface.cs +++ b/src/Avalonia.OpenGL/Angle/AngleEglInterface.cs @@ -1,15 +1,13 @@ using System; using System.Runtime.InteropServices; using Avalonia.OpenGL.Egl; -using Avalonia.Platform; -using Avalonia.Platform.Interop; namespace Avalonia.OpenGL.Angle { public class AngleEglInterface : EglInterface { - [DllImport("libegl.dll", CharSet = CharSet.Ansi)] - static extern IntPtr eglGetProcAddress(string proc); + [DllImport("av_libGLESv2.dll", CharSet = CharSet.Ansi)] + static extern IntPtr EGL_GetProcAddress(string proc); public AngleEglInterface() : base(LoadAngle()) { @@ -20,14 +18,14 @@ namespace Avalonia.OpenGL.Angle { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - var disp = eglGetProcAddress("eglGetPlatformDisplayEXT"); + var disp = EGL_GetProcAddress("eglGetPlatformDisplayEXT"); if (disp == IntPtr.Zero) { throw new OpenGlException("libegl.dll doesn't have eglGetPlatformDisplayEXT entry point"); } - return eglGetProcAddress; + return EGL_GetProcAddress; } throw new PlatformNotSupportedException(); diff --git a/src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs b/src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs index 191fb53204..94e7728d68 100644 --- a/src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs +++ b/src/Avalonia.OpenGL/Angle/AngleWin32EglDisplay.cs @@ -82,7 +82,14 @@ namespace Avalonia.OpenGL.Angle { if (PlatformApi != AngleOptions.PlatformApi.DirectX11) throw new InvalidOperationException("Current platform API is " + PlatformApi); - return egl.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_NONE, EGL_NONE }); + return egl.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_NONE, EGL_NONE }); + } + + public EglSurface WrapDirect3D11Texture(EglPlatformOpenGlInterface egl, IntPtr handle, int offsetX, int offsetY, int width, int height) + { + if (PlatformApi != AngleOptions.PlatformApi.DirectX11) + throw new InvalidOperationException("Current platform API is " + PlatformApi); + return egl.CreatePBufferFromClientBuffer(EGL_D3D_TEXTURE_ANGLE, handle, new[] { EGL_WIDTH, width, EGL_HEIGHT, height, EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE, EGL_TRUE, EGL_TEXTURE_OFFSET_X_ANGLE, offsetX, EGL_TEXTURE_OFFSET_Y_ANGLE, offsetY, EGL_NONE }); } } } diff --git a/src/Avalonia.OpenGL/Egl/EglConsts.cs b/src/Avalonia.OpenGL/Egl/EglConsts.cs index 58f5f1cef5..530d3401f6 100644 --- a/src/Avalonia.OpenGL/Egl/EglConsts.cs +++ b/src/Avalonia.OpenGL/Egl/EglConsts.cs @@ -205,5 +205,11 @@ namespace Avalonia.OpenGL.Egl public const int EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE = 0x3200; public const int EGL_D3D_TEXTURE_ANGLE = 0x33A3; + + + public const int EGL_TEXTURE_OFFSET_X_ANGLE = 0x3490; + public const int EGL_TEXTURE_OFFSET_Y_ANGLE = 0x3491; + + public const int EGL_FLEXIBLE_SURFACE_COMPATIBILITY_SUPPORTED_ANGLE = 0x33A6; } } diff --git a/src/Avalonia.ReactiveUI.Events/Avalonia.ReactiveUI.Events.csproj b/src/Avalonia.ReactiveUI.Events/Avalonia.ReactiveUI.Events.csproj index 75eeb92f42..7f58e455f9 100644 --- a/src/Avalonia.ReactiveUI.Events/Avalonia.ReactiveUI.Events.csproj +++ b/src/Avalonia.ReactiveUI.Events/Avalonia.ReactiveUI.Events.csproj @@ -2,6 +2,7 @@ netstandard2.0 Avalonia.ReactiveUI.Events + false diff --git a/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj b/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj index d01a495108..624c5772a9 100644 --- a/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj +++ b/src/Avalonia.ReactiveUI/Avalonia.ReactiveUI.csproj @@ -2,6 +2,7 @@ netstandard2.0 Avalonia.ReactiveUI + false diff --git a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs index fc48a8853d..31f4691c90 100644 --- a/src/Avalonia.ReactiveUI/ReactiveUserControl.cs +++ b/src/Avalonia.ReactiveUI/ReactiveUserControl.cs @@ -1,3 +1,6 @@ +using System; +using System.Reactive.Disposables; +using System.Reactive.Linq; using Avalonia; using Avalonia.VisualTree; using Avalonia.Controls; @@ -6,8 +9,10 @@ using ReactiveUI; namespace Avalonia.ReactiveUI { /// - /// A ReactiveUI UserControl that implements - /// and will activate your ViewModel automatically if it supports activation. + /// A ReactiveUI that implements the interface and + /// will activate your ViewModel automatically if the view model implements . + /// When the DataContext property changes, this class will update the ViewModel property with the new DataContext + /// value, and vice versa. /// /// ViewModel type. public class ReactiveUserControl : UserControl, IViewFor where TViewModel : class @@ -20,7 +25,14 @@ namespace Avalonia.ReactiveUI /// public ReactiveUserControl() { - DataContextChanged += (sender, args) => ViewModel = DataContext as TViewModel; + // This WhenActivated block calls ViewModel's WhenActivated + // block if the ViewModel implements IActivatableViewModel. + this.WhenActivated(disposables => { }); + + this.ObservableForProperty(x => x.ViewModel, false, true) + .Subscribe(args => DataContext = args.Value); + this.ObservableForProperty(x => x.DataContext, false, true) + .Subscribe(args => ViewModel = args.Value as TViewModel); } /// diff --git a/src/Avalonia.ReactiveUI/ReactiveWindow.cs b/src/Avalonia.ReactiveUI/ReactiveWindow.cs index 5695a727af..1204266b63 100644 --- a/src/Avalonia.ReactiveUI/ReactiveWindow.cs +++ b/src/Avalonia.ReactiveUI/ReactiveWindow.cs @@ -1,3 +1,6 @@ +using System; +using System.Reactive.Disposables; +using System.Reactive.Linq; using Avalonia; using Avalonia.VisualTree; using Avalonia.Controls; @@ -6,8 +9,10 @@ using ReactiveUI; namespace Avalonia.ReactiveUI { /// - /// A ReactiveUI Window that implements - /// and will activate your ViewModel automatically if it supports activation. + /// A ReactiveUI that implements the interface and will + /// activate your ViewModel automatically if the view model implements . When + /// the DataContext property changes, this class will update the ViewModel property with the new DataContext value, + /// and vice versa. /// /// ViewModel type. public class ReactiveWindow : Window, IViewFor where TViewModel : class @@ -20,7 +25,14 @@ namespace Avalonia.ReactiveUI /// public ReactiveWindow() { - DataContextChanged += (sender, args) => ViewModel = DataContext as TViewModel; + // This WhenActivated block calls ViewModel's WhenActivated + // block if the ViewModel implements IActivatableViewModel. + this.WhenActivated(disposables => { }); + + this.ObservableForProperty(x => x.ViewModel, false, true) + .Subscribe(args => DataContext = args.Value); + this.ObservableForProperty(x => x.DataContext, false, true) + .Subscribe(args => ViewModel = args.Value as TViewModel); } /// diff --git a/src/Avalonia.Styling/Properties/AssemblyInfo.cs b/src/Avalonia.Styling/Properties/AssemblyInfo.cs index b231f3b406..34c71fffe3 100644 --- a/src/Avalonia.Styling/Properties/AssemblyInfo.cs +++ b/src/Avalonia.Styling/Properties/AssemblyInfo.cs @@ -5,4 +5,8 @@ using Avalonia.Metadata; [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Controls")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.LogicalTree")] [assembly: XmlnsDefinition("https://github.com/avaloniaui", "Avalonia.Styling")] -[assembly: InternalsVisibleTo("Avalonia.Styling.UnitTests")] \ No newline at end of file +#if SIGNED_BUILD +[assembly: InternalsVisibleTo("Avalonia.Styling.UnitTests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c1bba1142285fe0419326fb25866ba62c47e6c2b5c1ab0c95b46413fad375471232cb81706932e1cef38781b9ebd39d5100401bacb651c6c5bbf59e571e81b3bc08d2a622004e08b1a6ece82a7e0b9857525c86d2b95fab4bc3dce148558d7f3ae61aa3a234086902aeface87d9dfdd32b9d2fe3c6dd4055b5ab4b104998bd87")] +#else +[assembly: InternalsVisibleTo("Avalonia.Styling.UnitTests")] +#endif diff --git a/src/Avalonia.Themes.Default/DefaultTheme.xaml b/src/Avalonia.Themes.Default/DefaultTheme.xaml index 625b409598..107fc07875 100644 --- a/src/Avalonia.Themes.Default/DefaultTheme.xaml +++ b/src/Avalonia.Themes.Default/DefaultTheme.xaml @@ -12,7 +12,8 @@ - + + diff --git a/src/Avalonia.Themes.Default/Label.xaml b/src/Avalonia.Themes.Default/Label.xaml new file mode 100644 index 0000000000..d93381aa69 --- /dev/null +++ b/src/Avalonia.Themes.Default/Label.xaml @@ -0,0 +1,17 @@ + diff --git a/src/Avalonia.Themes.Default/SplitView.xaml b/src/Avalonia.Themes.Default/SplitView.xaml index 2fb59cdbc4..18da3edb46 100644 --- a/src/Avalonia.Themes.Default/SplitView.xaml +++ b/src/Avalonia.Themes.Default/SplitView.xaml @@ -32,12 +32,12 @@ ClipToBounds="True" HorizontalAlignment="Left" ZIndex="100"> - + - + @@ -106,14 +106,14 @@ ClipToBounds="True" HorizontalAlignment="Right" ZIndex="100"> - + - + diff --git a/src/Avalonia.Themes.Fluent/ButtonSpinner.xaml b/src/Avalonia.Themes.Fluent/ButtonSpinner.xaml index 82265ea282..12b4845522 100644 --- a/src/Avalonia.Themes.Fluent/ButtonSpinner.xaml +++ b/src/Avalonia.Themes.Fluent/ButtonSpinner.xaml @@ -65,56 +65,59 @@ - - - + + + + - - - - + + + + - - - - - - + + + + + + + diff --git a/src/Avalonia.Themes.Fluent/ComboBox.xaml b/src/Avalonia.Themes.Fluent/ComboBox.xaml index 8155264f18..2eee656dc6 100644 --- a/src/Avalonia.Themes.Fluent/ComboBox.xaml +++ b/src/Avalonia.Themes.Fluent/ComboBox.xaml @@ -44,105 +44,107 @@ - - + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - - - - + Grid.Column="1" + IsHitTestVisible="False" + Margin="0,0,10,0" + Height="12" + Width="12" + HorizontalAlignment="Right" + VerticalAlignment="Center"> + + + + + + + + + + + + + + @@ -232,4 +234,9 @@ + + + diff --git a/src/Avalonia.Themes.Fluent/DataValidationErrors.xaml b/src/Avalonia.Themes.Fluent/DataValidationErrors.xaml index 902fc74c0c..ed31f7b573 100644 --- a/src/Avalonia.Themes.Fluent/DataValidationErrors.xaml +++ b/src/Avalonia.Themes.Fluent/DataValidationErrors.xaml @@ -14,39 +14,31 @@ - - + + - - - - - - - - - - + + + + + + + diff --git a/src/Avalonia.Themes.Fluent/DatePicker.xaml b/src/Avalonia.Themes.Fluent/DatePicker.xaml index 6fbfa1bbf7..b6e36861e0 100644 --- a/src/Avalonia.Themes.Fluent/DatePicker.xaml +++ b/src/Avalonia.Themes.Fluent/DatePicker.xaml @@ -125,77 +125,79 @@ - - + + + - + - - - + + + - + + @@ -228,6 +230,11 @@ + + + diff --git a/src/Avalonia.Themes.Fluent/NumericUpDown.xaml b/src/Avalonia.Themes.Fluent/NumericUpDown.xaml index cc5e2234f8..1da48ebd8a 100644 --- a/src/Avalonia.Themes.Fluent/NumericUpDown.xaml +++ b/src/Avalonia.Themes.Fluent/NumericUpDown.xaml @@ -39,6 +39,7 @@ VerticalContentAlignment="Stretch" AllowSpin="{TemplateBinding AllowSpin}" ShowButtonSpinner="{TemplateBinding ShowButtonSpinner}" + DataValidationErrors.Errors="{TemplateBinding (DataValidationErrors.Errors)}" ButtonSpinnerLocation="{TemplateBinding ButtonSpinnerLocation}"> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -102,56 +104,58 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + @@ -260,4 +264,12 @@ + + + + diff --git a/src/Avalonia.Themes.Fluent/SplitView.xaml b/src/Avalonia.Themes.Fluent/SplitView.xaml index 71e92459f1..7d6f7a9b9a 100644 --- a/src/Avalonia.Themes.Fluent/SplitView.xaml +++ b/src/Avalonia.Themes.Fluent/SplitView.xaml @@ -32,12 +32,12 @@ ClipToBounds="True" HorizontalAlignment="Left" ZIndex="100"> - + - + @@ -106,14 +106,14 @@ ClipToBounds="True" HorizontalAlignment="Right" ZIndex="100"> - + - + diff --git a/src/Avalonia.Themes.Fluent/TextBox.xaml b/src/Avalonia.Themes.Fluent/TextBox.xaml index 162835ae10..139a61abdf 100644 --- a/src/Avalonia.Themes.Fluent/TextBox.xaml +++ b/src/Avalonia.Themes.Fluent/TextBox.xaml @@ -36,16 +36,7 @@ - - - - - + - - - + - - + diff --git a/src/Avalonia.Themes.Fluent/TimePicker.xaml b/src/Avalonia.Themes.Fluent/TimePicker.xaml index 84352213e1..91969d8733 100644 --- a/src/Avalonia.Themes.Fluent/TimePicker.xaml +++ b/src/Avalonia.Themes.Fluent/TimePicker.xaml @@ -41,94 +41,96 @@ - - + + + - + Width="{DynamicResource TimePickerSpacerThemeWidth}" + Grid.Column="3" /> + + + + + + - - - + + + - + + @@ -161,6 +163,10 @@ + +