diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json index d2f2ee36d5..b802589fc7 100644 --- a/.nuke/build.schema.json +++ b/.nuke/build.schema.json @@ -6,17 +6,18 @@ "build": { "type": "object", "properties": { - "Configuration": { - "type": "string", - "description": "configuration" + "api-baseline": { + "type": "string" + }, + "configuration": { + "type": "string" }, "Continue": { "type": "boolean", "description": "Indicates to continue a previously failed build attempt" }, - "ForceNugetVersion": { - "type": "string", - "description": "force-nuget-version" + "force-nuget-version": { + "type": "string" }, "Help": { "type": "boolean", @@ -89,17 +90,16 @@ "RunRenderTests", "RunTests", "RunToolsTests", + "ValidateApiDiff", "ZipFiles" ] } }, - "SkipPreviewer": { - "type": "boolean", - "description": "skip-previewer" + "skip-previewer": { + "type": "boolean" }, - "SkipTests": { - "type": "boolean", - "description": "skip-tests" + "skip-tests": { + "type": "boolean" }, "Target": { "type": "array", @@ -124,10 +124,14 @@ "RunRenderTests", "RunTests", "RunToolsTests", + "ValidateApiDiff", "ZipFiles" ] } }, + "update-api-suppression": { + "type": "boolean" + }, "Verbosity": { "type": "string", "description": "Logging verbosity during build execution. Default is 'Normal'", diff --git a/Documentation/build.md b/Documentation/build.md index fd6b26337c..3fcaae8963 100644 --- a/Documentation/build.md +++ b/Documentation/build.md @@ -14,6 +14,18 @@ git submodule update --init Go to https://dotnet.microsoft.com/download/visual-studio-sdks and install the latest version of the .NET Core SDK compatible with Avalonia UI. Make sure to download the SDK (not just the "runtime") package. The version compatible is indicated within the [global.json](https://github.com/AvaloniaUI/Avalonia/blob/master/global.json) file. Note that Avalonia UI does not always use the latest version and is hardcoded to use the last version known to be compatible (SDK releases may break the builds from time-to-time). +### Installing necessary .NET Workloads + +.NET SDK requires developers to install workloads for each platform they are targeting. +Since Avalonia targets pretty much every supported .NET platform, you need to install these workloads as well. +Running it from the command line: +``` +dotnet workload install android ios wasm-tools wasm-experimental +``` + +macOS workloads are not required to build Avalonia. +Note: on Unix OS you need to run this command from sudo. + ## Build and Run Avalonia ``` @@ -43,6 +55,25 @@ Build and run `ControlCatalog.NetCore` project to see the sample application. >CSC : error CS0006: Metadata file 'C:\...\Avalonia\packages\Avalonia\bin\Debug\netcoreapp2.0\Avalonia.dll' could not be found ``` To correct this, right click on the `Avalonia.DesktopRuntime` project then press `Build` to build the project manually. Afterwards the solution should build normally and the ControlCatalog can be run. + * **Error MSB4062 GenerateAvaloniaResourcesTask** + + Same as previous one, you need to manually build `Avalonia.Build.Tasks` project at least once. + + Alternatively, you can build the solution once with Nuke. + +## Building packages with Nuke + +Install Nuke +`dotnet tool install --global Nuke.GlobalTool --version 6.2.1` + +Build project: +`nuke --target Compile --configuration Release` + +And run tests: +`nuke --target RunTests --configuration Release` + +Or if you need to create nuget packages as well (it will compile and run tests automatically): +`nuke --target Package --configuration Release` # Linux/macOS diff --git a/api/Avalonia.Controls.ColorPicker.nupkg.xml b/api/Avalonia.Controls.ColorPicker.nupkg.xml new file mode 100644 index 0000000000..90271d6e98 --- /dev/null +++ b/api/Avalonia.Controls.ColorPicker.nupkg.xml @@ -0,0 +1,64 @@ + + + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorPicker.xaml + baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll + target/netstandard2.0/Avalonia.Controls.ColorPicker.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorPreviewer.xaml + baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll + target/netstandard2.0/Avalonia.Controls.ColorPicker.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorSlider.xaml + baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll + target/netstandard2.0/Avalonia.Controls.ColorPicker.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorSpectrum.xaml + baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll + target/netstandard2.0/Avalonia.Controls.ColorPicker.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Fluent/ColorView.xaml + baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll + target/netstandard2.0/Avalonia.Controls.ColorPicker.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorPicker.xaml + baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll + target/netstandard2.0/Avalonia.Controls.ColorPicker.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorPreviewer.xaml + baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll + target/netstandard2.0/Avalonia.Controls.ColorPicker.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorSlider.xaml + baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll + target/netstandard2.0/Avalonia.Controls.ColorPicker.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorSpectrum.xaml + baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll + target/netstandard2.0/Avalonia.Controls.ColorPicker.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Themes/Simple/ColorView.xaml + baseline/netstandard2.0/Avalonia.Controls.ColorPicker.dll + target/netstandard2.0/Avalonia.Controls.ColorPicker.dll + + \ No newline at end of file diff --git a/api/Avalonia.Themes.Fluent.nupkg.xml b/api/Avalonia.Themes.Fluent.nupkg.xml new file mode 100644 index 0000000000..f35bf5a629 --- /dev/null +++ b/api/Avalonia.Themes.Fluent.nupkg.xml @@ -0,0 +1,418 @@ + + + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Accents/BaseResources.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Accents/FluentControlResources.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/AdornerLayer.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/AutoCompleteBox.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Button.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ButtonSpinner.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Calendar.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarDatePicker.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarDayButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CaptionButtons.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Carousel.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CheckBox.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ComboBox.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ComboBoxItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ContentControl.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ContextMenu.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DataValidationErrors.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DatePicker.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DateTimePickerShared.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DropDownButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/EmbeddableControlRoot.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Expander.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/FlyoutPresenter.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/GridSplitter.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ItemsControl.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Label.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ListBox.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ListBoxItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ManagedFileChooser.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Menu.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuFlyoutPresenter.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuScrollViewer.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NativeMenuBar.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NotificationCard.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NumericUpDown.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/OverlayPopupHost.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/PathIcon.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/PopupRoot.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ProgressBar.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RadioButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RefreshContainer.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RefreshVisualizer.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RepeatButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ScrollBar.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ScrollViewer.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SelectableTextBlock.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Separator.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Slider.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SplitButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SplitView.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabControl.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabStrip.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabStripItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TextBox.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ThemeVariantScope.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TimePicker.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TitleBar.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToggleButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToggleSwitch.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToolTip.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TransitioningContentControl.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TreeView.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TreeViewItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Window.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/WindowNotificationManager.xaml + baseline/netstandard2.0/Avalonia.Themes.Fluent.dll + target/netstandard2.0/Avalonia.Themes.Fluent.dll + + \ No newline at end of file diff --git a/api/Avalonia.Themes.Simple.nupkg.xml b/api/Avalonia.Themes.Simple.nupkg.xml new file mode 100644 index 0000000000..78d8c4b332 --- /dev/null +++ b/api/Avalonia.Themes.Simple.nupkg.xml @@ -0,0 +1,406 @@ + + + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Accents/Base.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/AdornerLayer.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/AutoCompleteBox.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Button.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ButtonSpinner.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Calendar.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarDatePicker.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarDayButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CalendarItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CaptionButtons.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Carousel.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/CheckBox.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ComboBox.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ComboBoxItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ContentControl.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ContextMenu.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DataValidationErrors.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DatePicker.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DateTimePickerShared.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/DropDownButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/EmbeddableControlRoot.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Expander.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/FlyoutPresenter.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/GridSplitter.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ItemsControl.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Label.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ListBox.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ListBoxItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ManagedFileChooser.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Menu.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuFlyoutPresenter.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/MenuItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NativeMenuBar.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NotificationCard.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/NumericUpDown.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/OverlayPopupHost.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/PathIcon.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/PopupRoot.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ProgressBar.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RadioButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RefreshContainer.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RefreshVisualizer.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/RepeatButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ScrollBar.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ScrollViewer.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SelectableTextBlock.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Separator.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Slider.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SplitButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/SplitView.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabControl.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabStrip.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TabStripItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TextBox.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ThemeVariantScope.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TimePicker.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TitleBar.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToggleButton.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToggleSwitch.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/ToolTip.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TransitioningContentControl.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TreeView.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/TreeViewItem.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/Window.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + + CP0001 + T:CompiledAvaloniaXaml.!AvaloniaResources.NamespaceInfo:/Controls/WindowNotificationManager.xaml + baseline/netstandard2.0/Avalonia.Themes.Simple.dll + target/netstandard2.0/Avalonia.Themes.Simple.dll + + \ No newline at end of file diff --git a/nukebuild/ApiDiffValidation.cs b/nukebuild/ApiDiffValidation.cs new file mode 100644 index 0000000000..bd576250bd --- /dev/null +++ b/nukebuild/ApiDiffValidation.cs @@ -0,0 +1,153 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Net.Http; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using Nuke.Common.Tooling; + +public static class ApiDiffValidation +{ + private static readonly HttpClient s_httpClient = new(); + + public static async Task ValidatePackage( + Tool apiCompatTool, string packagePath, string baselineVersion, + string suppressionFilesFolder, bool updateSuppressionFile) + { + if (baselineVersion is null) + { + throw new InvalidOperationException( + "Build \"api-baseline\" parameter must be set when running Nuke CreatePackages"); + } + + if (!Directory.Exists(suppressionFilesFolder)) + { + Directory.CreateDirectory(suppressionFilesFolder!); + } + + await using (var baselineStream = await DownloadBaselinePackage(packagePath, baselineVersion)) + using (var target = new ZipArchive(File.Open(packagePath, FileMode.Open, FileAccess.Read), ZipArchiveMode.Read)) + using (var baseline = new ZipArchive(baselineStream, ZipArchiveMode.Read)) + using (Helpers.UseTempDir(out var tempFolder)) + { + var targetDlls = GetDlls(target); + var baselineDlls = GetDlls(baseline); + + var left = new List(); + var right = new List(); + + var suppressionFile = Path.Combine(suppressionFilesFolder, GetPackageId(packagePath) + ".nupkg.xml"); + + // Don't use Path.Combine with these left and right tool parameters. + // Microsoft.DotNet.ApiCompat.Tool is stupid and treats '/' and '\' as different assemblies in suppression files. + // So, always use Unix '/' + foreach (var baselineDll in baselineDlls) + { + var baselineDllPath = $"baseline/{baselineDll.target}/{baselineDll.entry.Name}"; + var baselineDllRealPath = Path.Combine(tempFolder, baselineDllPath); + Directory.CreateDirectory(Path.GetDirectoryName(baselineDllRealPath)!); + await using (var baselineDllFile = File.Create(baselineDllRealPath)) + { + await baselineDll.entry.Open().CopyToAsync(baselineDllFile); + } + + var targetDll = targetDlls.FirstOrDefault(e => + e.target == baselineDll.target && e.entry.Name == baselineDll.entry.Name); + if (targetDll.entry is null) + { + throw new InvalidOperationException($"Some assemblies are missing in the new package: {baselineDll.entry.Name} for {baselineDll.target}"); + } + + var targetDllPath = $"target/{targetDll.target}/{targetDll.entry.Name}"; + var targetDllRealPath = Path.Combine(tempFolder, targetDllPath); + Directory.CreateDirectory(Path.GetDirectoryName(targetDllRealPath)!); + await using (var targetDllFile = File.Create(targetDllRealPath)) + { + await targetDll.entry.Open().CopyToAsync(targetDllFile); + } + + left.Add(baselineDllPath); + right.Add(targetDllPath); + } + + if (left.Any()) + { + var args = $""" -l={string.Join(',', left)} -r="{string.Join(',', right)}" """; + if (File.Exists(suppressionFile)) + { + args += $""" --suppression-file="{suppressionFile}" """; + } + + if (updateSuppressionFile) + { + args += $""" --suppression-output-file="{suppressionFile}" --generate-suppression-file=true """; + } + + var result = apiCompatTool(args, tempFolder) + .Where(t => t.Type == OutputType.Err).ToArray(); + if (result.Any()) + { + throw new AggregateException( + $"ApiDiffValidation task has failed for \"{Path.GetFileName(packagePath)}\" package", + result.Select(r => new Exception(r.Text))); + } + } + } + } + + private static IReadOnlyCollection<(string target, ZipArchiveEntry entry)> GetDlls(ZipArchive archive) + { + return archive.Entries + .Where(e => Path.GetExtension(e.FullName) == ".dll" + // Exclude analyzers and build task, as we don't care about breaking changes there + && !e.FullName.Contains("analyzers/") && !e.FullName.Contains("analyzers\\") + && !e.Name.Contains("Avalonia.Build.Tasks")) + .Select(e => ( + entry: e, + isRef: e.FullName.Contains("ref/") || e.FullName.Contains("ref\\"), + target: Path.GetDirectoryName(e.FullName)!.Split(new [] { '/', '\\' }).Last()) + ) + .GroupBy(e => (e.target, e.entry.Name)) + .Select(g => g.MaxBy(e => e.isRef)) + .Select(e => (e.target, e.entry)) + .ToArray(); + } + + static async Task DownloadBaselinePackage(string packagePath, string baselineVersion) + { + /* + Gets package name from versions like: + Avalonia.0.10.0-preview1 + Avalonia.11.0.999-cibuild0037534-beta + Avalonia.11.0.0 + */ + var packageId = GetPackageId(packagePath); + Build.Information("Downloading {0} {1} baseline package", packageId, baselineVersion); + + try + { + using var response = await s_httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, + $"https://www.nuget.org/api/v2/package/{packageId}/{baselineVersion}"), HttpCompletionOption.ResponseHeadersRead); + response.EnsureSuccessStatusCode(); + + await using var stream = await response.Content.ReadAsStreamAsync(); + var memoryStream = new MemoryStream(); + await stream.CopyToAsync(memoryStream); + memoryStream.Seek(0, SeekOrigin.Begin); + return memoryStream; + } + catch (Exception ex) + { + throw new InvalidOperationException($"Downloading baseline package for {packageId} {baselineVersion} failed.\r" + ex.Message, ex); + } + } + + static string GetPackageId(string packagePath) + { + return Regex.Replace( + Path.GetFileNameWithoutExtension(packagePath), + """(\.\d+\.\d+\.\d+(?:-.+)?)$""", ""); + } +} diff --git a/nukebuild/Build.cs b/nukebuild/Build.cs index 524c9fa4e4..b82c446249 100644 --- a/nukebuild/Build.cs +++ b/nukebuild/Build.cs @@ -36,6 +36,10 @@ using MicroCom.CodeGenerator; partial class Build : NukeBuild { BuildParameters Parameters { get; set; } + + [PackageExecutable("Microsoft.DotNet.ApiCompat.Tool", "Microsoft.DotNet.ApiCompat.Tool.dll", Framework = "net6.0")] + Tool ApiCompatTool; + protected override void OnBuildInitialized() { Parameters = new BuildParameters(this); @@ -278,7 +282,17 @@ partial class Build : NukeBuild RefAssemblyGenerator.GenerateRefAsmsInPackage(Parameters.NugetRoot / "Avalonia." + Parameters.Version + ".nupkg"); }); - + + Target ValidateApiDiff => _ => _ + .DependsOn(CreateNugetPackages) + .Executes(async () => + { + await Task.WhenAll( + Directory.GetFiles(Parameters.NugetRoot).Select(nugetPackage => ApiDiffValidation.ValidatePackage( + ApiCompatTool, nugetPackage, Parameters.ApiValidationBaseline, + Parameters.ApiValidationSuppressionFiles, Parameters.UpdateApiValidationSuppression))); + }); + Target RunTests => _ => _ .DependsOn(RunCoreLibsTests) .DependsOn(RunRenderTests) @@ -288,7 +302,8 @@ partial class Build : NukeBuild Target Package => _ => _ .DependsOn(RunTests) - .DependsOn(CreateNugetPackages); + .DependsOn(CreateNugetPackages) + .DependsOn(ValidateApiDiff); Target CiAzureLinux => _ => _ .DependsOn(RunTests); diff --git a/nukebuild/BuildParameters.cs b/nukebuild/BuildParameters.cs index dfa914d1db..897fdc84f1 100644 --- a/nukebuild/BuildParameters.cs +++ b/nukebuild/BuildParameters.cs @@ -10,18 +10,24 @@ using static Nuke.Common.IO.PathConstruction; public partial class Build { - [Parameter("configuration")] + [Parameter(Name = "configuration")] public string Configuration { get; set; } - [Parameter("skip-tests")] + [Parameter(Name = "skip-tests")] public bool SkipTests { get; set; } - [Parameter("force-nuget-version")] + [Parameter(Name = "force-nuget-version")] public string ForceNugetVersion { get; set; } - [Parameter("skip-previewer")] + [Parameter(Name = "skip-previewer")] public bool SkipPreviewer { get; set; } + [Parameter(Name = "api-baseline")] + public string ApiValidationBaseline { get; set; } + + [Parameter(Name = "update-api-suppression")] + public bool? UpdateApiValidationSuppression { get; set; } + public class BuildParameters { public string Configuration { get; } @@ -57,7 +63,9 @@ public partial class Build public string FileZipSuffix { get; } public AbsolutePath ZipCoreArtifacts { get; } public AbsolutePath ZipNuGetArtifacts { get; } - + public string ApiValidationBaseline { get; } + public bool UpdateApiValidationSuppression { get; } + public AbsolutePath ApiValidationSuppressionFiles { get; } public BuildParameters(Build b) { @@ -103,6 +111,9 @@ public partial class Build // VERSION Version = b.ForceNugetVersion ?? GetVersion(); + ApiValidationBaseline = b.ApiValidationBaseline ?? new Version(new Version(Version).Major, 0).ToString(); + UpdateApiValidationSuppression = b.UpdateApiValidationSuppression ?? IsLocalBuild; + if (IsRunningOnAzure) { if (!IsNuGetRelease) @@ -125,6 +136,7 @@ public partial class Build FileZipSuffix = Version + ".zip"; ZipCoreArtifacts = ZipRoot / ("Avalonia-" + FileZipSuffix); ZipNuGetArtifacts = ZipRoot / ("Avalonia-NuGet-" + FileZipSuffix); + ApiValidationSuppressionFiles = RootDirectory / "api"; } string GetVersion() diff --git a/nukebuild/Shims.cs b/nukebuild/Shims.cs index 6f79972ad6..eecfcf6da1 100644 --- a/nukebuild/Shims.cs +++ b/nukebuild/Shims.cs @@ -9,12 +9,12 @@ using Numerge; public partial class Build { - static void Information(string info) + internal static void Information(string info) { Logger.Info(info); } - static void Information(string info, params object[] args) + internal static void Information(string info, params object[] args) { Logger.Info(info, args); } diff --git a/nukebuild/_build.csproj b/nukebuild/_build.csproj index 30e1200220..43453833d7 100644 --- a/nukebuild/_build.csproj +++ b/nukebuild/_build.csproj @@ -22,6 +22,8 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + diff --git a/readme.md b/readme.md index e9cd220714..fc5e218a92 100644 --- a/readme.md +++ b/readme.md @@ -6,18 +6,16 @@
[![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](https://github.com/AvaloniaUI/Avalonia/discussions/10599)** - ## 📖 About [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. +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/docs/next/get-started/wpf/), it isn't a 1:1 copy, and you'll find plenty of improvements. 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. #### Roadmap -To see the status of some of our features, please see our [Roadmap](https://github.com/AvaloniaUI/Avalonia/issues/2239). +To see the status of some of our features, look at 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. diff --git a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml index a492808f1d..b682ebf51d 100644 --- a/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml +++ b/samples/ControlCatalog/Pages/AutoCompleteBoxPage.xaml @@ -18,6 +18,10 @@ + + + + @@ -42,7 +46,6 @@ - diff --git a/samples/ControlCatalog/Pages/DataGridPage.xaml b/samples/ControlCatalog/Pages/DataGridPage.xaml index fb097da71b..356834832d 100644 --- a/samples/ControlCatalog/Pages/DataGridPage.xaml +++ b/samples/ControlCatalog/Pages/DataGridPage.xaml @@ -34,7 +34,7 @@ RowBackground="#1000"> - + @@ -68,7 +68,7 @@ - + diff --git a/src/Avalonia.Base/Interactivity/EventRoute.cs b/src/Avalonia.Base/Interactivity/EventRoute.cs index 37539a7153..d0d82b4884 100644 --- a/src/Avalonia.Base/Interactivity/EventRoute.cs +++ b/src/Avalonia.Base/Interactivity/EventRoute.cs @@ -120,11 +120,6 @@ namespace Avalonia.Interactivity return; } - if (e.Source is null) - { - throw new ArgumentException("Event source may not be null", nameof(e)); - } - Interactive? lastTarget = null; var start = 0; var end = _route.Count; diff --git a/src/Avalonia.Base/Platform/Storage/PickerOptions.cs b/src/Avalonia.Base/Platform/Storage/PickerOptions.cs index ed061aa2d5..07f99f32c8 100644 --- a/src/Avalonia.Base/Platform/Storage/PickerOptions.cs +++ b/src/Avalonia.Base/Platform/Storage/PickerOptions.cs @@ -6,7 +6,7 @@ public class PickerOptions { /// - /// Gets or sets the text that appears in the title bar of a folder dialog. + /// Gets or sets the text that appears in the title bar of a picker. /// public string? Title { get; set; } diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionExternalMemory.cs b/src/Avalonia.Base/Rendering/Composition/CompositionExternalMemory.cs index 1021bc58b4..ce728f86a2 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionExternalMemory.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionExternalMemory.cs @@ -91,8 +91,7 @@ public interface ICompositionGpuImportedObject : IAsyncDisposable /// the user code is allowed to free the resource owner in case when a non-owning /// sharing handle was used /// - Task ImportCompleted { get; } - + Task ImportCompeted { get; } /// /// Indicates if the device context this instance is associated with is no longer available /// diff --git a/src/Avalonia.Base/Rendering/Composition/CompositionInterop.cs b/src/Avalonia.Base/Rendering/Composition/CompositionInterop.cs index 9eea228e84..1643ec6e8d 100644 --- a/src/Avalonia.Base/Rendering/Composition/CompositionInterop.cs +++ b/src/Avalonia.Base/Rendering/Composition/CompositionInterop.cs @@ -67,18 +67,18 @@ abstract class CompositionGpuImportedObjectBase : ICompositionGpuImportedObject Context = context; Feature = feature; - ImportCompleted = Compositor.InvokeServerJobAsync(Import); + ImportCompeted = Compositor.InvokeServerJobAsync(Import); } protected abstract void Import(); public abstract void Dispose(); - public Task ImportCompleted { get; } + public Task ImportCompeted { get; } public bool IsLost => Context.IsLost; public ValueTask DisposeAsync() => new(Compositor.InvokeServerJobAsync(() => { - if (ImportCompleted.Status == TaskStatus.RanToCompletion) + if (ImportCompeted.Status == TaskStatus.RanToCompletion) Dispose(); })); } diff --git a/src/Avalonia.Base/Rendering/Composition/Drawing/ServerCompositionRenderData.cs b/src/Avalonia.Base/Rendering/Composition/Drawing/ServerCompositionRenderData.cs index cb5e21be00..97083ccaf5 100644 --- a/src/Avalonia.Base/Rendering/Composition/Drawing/ServerCompositionRenderData.cs +++ b/src/Avalonia.Base/Rendering/Composition/Drawing/ServerCompositionRenderData.cs @@ -42,22 +42,31 @@ class ServerCompositionRenderData : SimpleServerRenderResource _items.Add(reader.ReadObject()); var collector = s_resourceHashSetPool.Get(); - foreach(var item in _items) - if (item is IRenderDataItemWithServerResources resourceItem) - resourceItem.Collect(collector); - + CollectResources(_items, collector); + foreach (var r in collector.Resources) { _referencedResources.Add(r); r.AddObserver(this); } - + collector.Resources.Clear(); s_resourceHashSetPool.ReturnAndSetNull(ref collector); base.DeserializeChangesCore(reader, committedAt); } + private static void CollectResources(PooledInlineList items, IRenderDataServerResourcesCollector collector) + { + foreach (var item in items) + { + if (item is IRenderDataItemWithServerResources resourceItem) + resourceItem.Collect(collector); + else if (item is RenderDataPushNode pushNode) + CollectResources(pushNode.Children, collector); + } + } + public Rect? Bounds { get @@ -133,4 +142,4 @@ class ServerCompositionRenderData : SimpleServerRenderResource Reset(); base.Dispose(); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawingSurface.cs b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawingSurface.cs index f58403f0bc..da24b3812a 100644 --- a/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawingSurface.cs +++ b/src/Avalonia.Base/Rendering/Composition/Server/ServerCompositionDrawingSurface.cs @@ -31,12 +31,12 @@ internal class ServerCompositionDrawingSurface : ServerCompositionSurface, IDisp throw new PlatformGraphicsContextLostException(); // This should never happen, but check for it anyway to avoid a deadlock - if (!image.ImportCompleted.IsCompleted) + if (!image.ImportCompeted.IsCompleted) throw new InvalidOperationException("The import operation is not completed yet"); // Rethrow the import here exception - if (image.ImportCompleted.IsFaulted) - image.ImportCompleted.GetAwaiter().GetResult(); + if (image.ImportCompeted.IsFaulted) + image.ImportCompeted.GetAwaiter().GetResult(); } void Update(IBitmapImpl newImage, IPlatformRenderInterfaceContext context) diff --git a/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs b/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs index 7d586e1cbd..25be5779b9 100644 --- a/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs +++ b/src/Avalonia.Base/Threading/Dispatcher.Invoke.cs @@ -90,7 +90,7 @@ public partial class Dispatcher { if (callback == null) { - throw new ArgumentNullException("callback"); + throw new ArgumentNullException(nameof(callback)); } DispatcherPriority.Validate(priority, "priority"); @@ -212,7 +212,7 @@ public partial class Dispatcher { if (callback == null) { - throw new ArgumentNullException("callback"); + throw new ArgumentNullException(nameof(callback)); } DispatcherPriority.Validate(priority, "priority"); @@ -304,7 +304,7 @@ public partial class Dispatcher { if (callback == null) { - throw new ArgumentNullException("callback"); + throw new ArgumentNullException(nameof(callback)); } DispatcherPriority.Validate(priority, "priority"); @@ -379,7 +379,7 @@ public partial class Dispatcher { if (callback == null) { - throw new ArgumentNullException("callback"); + throw new ArgumentNullException(nameof(callback)); } DispatcherPriority.Validate(priority, "priority"); diff --git a/src/Avalonia.Base/Threading/DispatcherTimer.cs b/src/Avalonia.Base/Threading/DispatcherTimer.cs index 879d9d8a5f..473b9eeefa 100644 --- a/src/Avalonia.Base/Threading/DispatcherTimer.cs +++ b/src/Avalonia.Base/Threading/DispatcherTimer.cs @@ -62,7 +62,7 @@ public partial class DispatcherTimer { if (callback == null) { - throw new ArgumentNullException("callback"); + throw new ArgumentNullException(nameof(callback)); } Tick += callback; @@ -253,7 +253,7 @@ public partial class DispatcherTimer { if (dispatcher == null) { - throw new ArgumentNullException("dispatcher"); + throw new ArgumentNullException(nameof(dispatcher)); } DispatcherPriority.Validate(priority, "priority"); diff --git a/src/Avalonia.Base/Utilities/SmallDictionary.cs b/src/Avalonia.Base/Utilities/SmallDictionary.cs index b6e62411da..1e63d554b4 100644 --- a/src/Avalonia.Base/Utilities/SmallDictionary.cs +++ b/src/Avalonia.Base/Utilities/SmallDictionary.cs @@ -51,7 +51,7 @@ internal struct InlineDictionary : IEnumerable : IEnumerable() @@ -353,10 +353,16 @@ namespace Avalonia.Build.Tasks ((List)parsedXamlDocuments).Add(new XamlDocumentResource( parsed, res.Uri, res, classType, classModifierPublic.Value, - populateBuilder, - compiler.DefinePopulateMethod(populateBuilder, parsed, populateName, - classTypeDefinition == null && classModifierPublic.Value), - buildName == null ? null : compiler.DefineBuildMethod(builder, parsed, buildName, classModifierPublic.Value))); + () => new XamlDocumentTypeBuilderProvider( + populateBuilder, + compiler.DefinePopulateMethod( + populateBuilder, + parsed, + populateName, + classTypeDefinition == null && classModifierPublic.Value), + buildName == null ? + null : + compiler.DefineBuildMethod(builder, parsed, buildName, classModifierPublic.Value)))); } catch (Exception e) { @@ -387,10 +393,17 @@ namespace Avalonia.Build.Tasks foreach (var document in parsedXamlDocuments) { + var res = (IResource)document.FileSource!; + + if (document.Usage == XamlDocumentUsage.Merged && !document.IsPublic) + { + res.Remove(); + continue; + } + var parsed = document.XamlDocument; - var res = (IResource)document.FileSource; var classType = document.ClassType; - var populateBuilder = document.TypeBuilder; + var populateBuilder = document.TypeBuilderProvider.TypeBuilder; try { @@ -399,8 +412,8 @@ namespace Avalonia.Build.Tasks compiler.Compile(parsed, contextClass, - document.PopulateMethod, - document.BuildMethod, + document.TypeBuilderProvider.PopulateMethod, + document.TypeBuilderProvider.BuildMethod, builder.DefineSubType(compilerConfig.WellKnownTypes.Object, "NamespaceInfo:" + res.Name, true), (closureName, closureBaseType) => populateBuilder.DefineSubType(closureBaseType, closureName, false), @@ -412,7 +425,7 @@ namespace Avalonia.Build.Tasks if (classTypeDefinition != null) { var compiledPopulateMethod = typeSystem.GetTypeReference(populateBuilder).Resolve() - .Methods.First(m => m.Name == document.PopulateMethod.Name); + .Methods.First(m => m.Name == document.TypeBuilderProvider.PopulateMethod.Name); var designLoaderFieldType = typeSystem .GetType("System.Action`1") @@ -536,12 +549,12 @@ namespace Avalonia.Build.Tasks } if (document.IsPublic - && (document.BuildMethod != null || classTypeDefinition != null)) + && (document.TypeBuilderProvider.BuildMethod != null || classTypeDefinition != null)) { - var compiledBuildMethod = document.BuildMethod == null ? + var compiledBuildMethod = document.TypeBuilderProvider.BuildMethod is not { } buildMethod ? null : typeSystem.GetTypeReference(builder).Resolve() - .Methods.First(m => m.Name == document.BuildMethod?.Name); + .Methods.First(m => m.Name == buildMethod.Name); var parameterlessConstructor = compiledBuildMethod != null ? null : classTypeDefinition.GetConstructors().FirstOrDefault(c => diff --git a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs index 5d080f5ef6..b2deb1c26e 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridCheckBoxColumn.cs @@ -222,7 +222,7 @@ namespace Avalonia.Controls { if (element == null) { - throw new ArgumentNullException("element"); + throw new ArgumentNullException(nameof(element)); } if (element is CheckBox checkBox) { diff --git a/src/Avalonia.Controls.DataGrid/DataGridColumnCollection.cs b/src/Avalonia.Controls.DataGrid/DataGridColumnCollection.cs index e7f9a9a6c4..798228c84c 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridColumnCollection.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridColumnCollection.cs @@ -191,7 +191,7 @@ namespace Avalonia.Controls } if (dataGridColumn == null) { - throw new ArgumentNullException("dataGridColumn"); + throw new ArgumentNullException(nameof(dataGridColumn)); } int columnIndexWithFiller = columnIndex; diff --git a/src/Avalonia.Controls.DataGrid/DataGridLength.cs b/src/Avalonia.Controls.DataGrid/DataGridLength.cs index 4841ddd494..a193352f52 100644 --- a/src/Avalonia.Controls.DataGrid/DataGridLength.cs +++ b/src/Avalonia.Controls.DataGrid/DataGridLength.cs @@ -499,7 +499,7 @@ namespace Avalonia.Controls { if (destinationType == null) { - throw new ArgumentNullException("destinationType"); + throw new ArgumentNullException(nameof(destinationType)); } if (destinationType != typeof(string)) { diff --git a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs index d0b894101f..ebf66164b7 100644 --- a/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs +++ b/src/Avalonia.Controls/AutoCompleteBox/AutoCompleteBox.cs @@ -1320,17 +1320,14 @@ namespace Avalonia.Controls // Evaluate the conditions needed for completion. // 1. Minimum prefix length // 2. If a delay timer is in use, use it - bool populateReady = newText.Length >= MinimumPrefixLength && MinimumPrefixLength >= 0; - if (populateReady && MinimumPrefixLength == 0 && String.IsNullOrEmpty(newText) && String.IsNullOrEmpty(SearchText)) - { - populateReady = false; - } - _userCalledPopulate = populateReady ? userInitiated : false; + bool minimumLengthReached = newText.Length >= MinimumPrefixLength && MinimumPrefixLength >= 0; + + _userCalledPopulate = minimumLengthReached && userInitiated; // Update the interface and values only as necessary UpdateTextValue(newText, userInitiated); - if (populateReady) + if (minimumLengthReached) { _ignoreTextSelectionChange = true; diff --git a/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs b/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs index 756951667b..c19d887230 100644 --- a/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs +++ b/src/Avalonia.Controls/Automation/Peers/ControlAutomationPeer.cs @@ -18,7 +18,7 @@ namespace Avalonia.Automation.Peers public ControlAutomationPeer(Control owner) { - Owner = owner ?? throw new ArgumentNullException("owner"); + Owner = owner ?? throw new ArgumentNullException(nameof(owner)); Initialize(); } diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs index 785fd49983..0002107ee0 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/EventTreeNode.cs @@ -72,12 +72,13 @@ namespace Avalonia.Diagnostics.ViewModels var s = sender!; var handled = e.Handled; var route = e.Route; + var triggerTime = DateTime.Now; void handler() { if (_currentEvent == null || !_currentEvent.IsPartOfSameEventChain(e)) { - _currentEvent = new FiredEvent(e, new EventChainLink(s, handled, route)); + _currentEvent = new FiredEvent(e, new EventChainLink(s, handled, route), triggerTime); _parentViewModel.RecordedEvents.Add(_currentEvent); diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/FiredEvent.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/FiredEvent.cs index a9f3182bef..1eab9afe8a 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/FiredEvent.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/FiredEvent.cs @@ -10,11 +10,12 @@ namespace Avalonia.Diagnostics.ViewModels private readonly RoutedEventArgs _eventArgs; private EventChainLink? _handledBy; - public FiredEvent(RoutedEventArgs eventArgs, EventChainLink originator) + public FiredEvent(RoutedEventArgs eventArgs, EventChainLink originator, DateTime triggerTime) { _eventArgs = eventArgs ?? throw new ArgumentNullException(nameof(eventArgs)); Originator = originator ?? throw new ArgumentNullException(nameof(originator)); AddToChain(originator); + TriggerTime = triggerTime; } public bool IsPartOfSameEventChain(RoutedEventArgs e) @@ -22,6 +23,8 @@ namespace Avalonia.Diagnostics.ViewModels return e == _eventArgs; } + public DateTime TriggerTime { get; } + public RoutedEvent Event => _eventArgs.RoutedEvent!; public bool IsHandled => HandledBy?.Handled == true; diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml index 54c2f06709..c18b8cf003 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/EventsPageView.xaml @@ -77,21 +77,23 @@ - + - + + + - + - + diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs index e2aab7d685..995ed91b8d 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/AvaloniaXamlIlRuntimeCompiler.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; @@ -231,10 +232,19 @@ namespace Avalonia.Markup.Xaml.XamlIl ?? ((IXamlAstValueNode)parsed.Root).Type.GetClrType().Name; var tb = _sreBuilder.DefineType("Builder_" + Guid.NewGuid().ToString("N") + "_" + xamlName); var builder = _sreTypeSystem.CreateTypeBuilder(tb); - parsedDocuments.Add(new XamlDocumentResource(parsed, document.BaseUri?.ToString(), - null, null, true, builder, - compiler.DefinePopulateMethod(builder, parsed, AvaloniaXamlIlCompiler.PopulateName, true), - document.RootInstance is null ? compiler.DefineBuildMethod(builder, parsed, AvaloniaXamlIlCompiler.BuildName, true) : null)); + + parsedDocuments.Add(new XamlDocumentResource( + parsed, + document.BaseUri?.ToString(), + null, + null, + true, + () => new XamlDocumentTypeBuilderProvider( + builder, + compiler.DefinePopulateMethod(builder, parsed, AvaloniaXamlIlCompiler.PopulateName, true), + document.RootInstance is null ? + compiler.DefineBuildMethod(builder, parsed, AvaloniaXamlIlCompiler.BuildName, true) : + null))); originalDocuments.Add(document); } @@ -242,9 +252,8 @@ namespace Avalonia.Markup.Xaml.XamlIl var createdTypes = parsedDocuments.Select(document => { - compiler.Compile(document.XamlDocument, document.TypeBuilder, document.PopulateMethod, - document.BuildMethod, document.Uri, document.FileSource); - return _sreTypeSystem.GetType(document.TypeBuilder.CreateType()); + compiler.Compile(document.XamlDocument, document.TypeBuilderProvider, document.Uri, document.FileSource); + return _sreTypeSystem.GetType(document.TypeBuilderProvider.TypeBuilder.CreateType()); }).ToArray(); clrPropertyBuilder.CreateTypeInfo(); diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs index 23c67df810..af34d55a3d 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlCompiler.cs @@ -179,9 +179,11 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions return parsed; } - public void Compile(XamlDocument document, IXamlTypeBuilder tb, IXamlMethodBuilder populateMethod, IXamlMethodBuilder buildMethod, string baseUri, IFileSource fileSource) + public void Compile(XamlDocument document, XamlDocumentTypeBuilderProvider typeBuilderProvider, string baseUri, IFileSource fileSource) { - Compile(document, _contextType, populateMethod, buildMethod, + var tb = typeBuilderProvider.TypeBuilder; + + Compile(document, _contextType, typeBuilderProvider.PopulateMethod, typeBuilderProvider.BuildMethod, _configuration.TypeMappings.XmlNamespaceInfoProvider == null ? null : tb.DefineSubType(_configuration.WellKnownTypes.Object, diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs index 8e04a7d467..f135ed5ffb 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/GroupTransformers/XamlMergeResourceGroupTransformer.cs @@ -3,8 +3,6 @@ using System.Collections.Generic; using System.Linq; using Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers; using XamlX.Ast; -using XamlX.IL.Emitters; -using XamlX.Transform.Transformers; using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.GroupTransformers; @@ -24,7 +22,6 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer var mergeResourceIncludeType = context.GetAvaloniaTypes().MergeResourceInclude; var mergeSourceNodes = new List(); - var mergedResourceWasAdded = false; foreach (var manipulationNode in resourceDictionaryManipulation.Children.ToArray()) { void ProcessXamlPropertyAssignmentNode(XamlManipulationGroupNode parent, XamlPropertyAssignmentNode assignmentNode) @@ -39,7 +36,6 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer { parent.Children.Remove(assignmentNode); mergeSourceNodes.Add(sourceAssignmentNode); - mergedResourceWasAdded = true; } else { @@ -85,25 +81,29 @@ internal class XamlMergeResourceGroupTransformer : IXamlAstGroupTransformer return context.ParseError( $"Node MergeResourceInclude is unable to resolve \"{originalAssetPath}\" path.", propertyNode, node); } - + var targetDocument = context.Documents.FirstOrDefault(d => - string.Equals(d.Uri, originalAssetPath, StringComparison.InvariantCultureIgnoreCase)) - ?.XamlDocument.Root as XamlValueWithManipulationNode; - if (targetDocument is null) + string.Equals(d.Uri, originalAssetPath, StringComparison.InvariantCultureIgnoreCase)); + if (targetDocument?.XamlDocument.Root is not XamlValueWithManipulationNode targetDocumentRoot) { return context.ParseError( $"Node MergeResourceInclude is unable to resolve \"{originalAssetPath}\" path.", propertyNode, node); } - var singleRootObject = ((XamlManipulationGroupNode)targetDocument.Manipulation) + var singleRootObject = ((XamlManipulationGroupNode)targetDocumentRoot.Manipulation) .Children.OfType().Single(); if (singleRootObject.Type != resourceDictionaryType) { return context.ParseError( - $"MergeResourceInclude can only include another ResourceDictionary", propertyNode, node); + "MergeResourceInclude can only include another ResourceDictionary", propertyNode, node); } manipulationGroup.Add(singleRootObject.Manipulation); + + if (targetDocument.Usage == XamlDocumentUsage.Unknown) + { + targetDocument.Usage = XamlDocumentUsage.Merged; + } } // Order of resources is defined by ResourceDictionary.TryGetResource. diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs index b859b3ed59..9b5c59682f 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/IXamlDocumentResource.cs @@ -1,5 +1,4 @@ -using System; -using XamlX.Ast; +using XamlX.Ast; using XamlX.TypeSystem; namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; @@ -14,4 +13,5 @@ internal interface IXamlDocumentResource IXamlMethod PopulateMethod { get; } IFileSource? FileSource { get; } XamlDocument XamlDocument { get; } + XamlDocumentUsage Usage { get; set; } } diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs index 932fe067af..0dab80d743 100644 --- a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentResource.cs @@ -1,6 +1,5 @@ using System; using XamlX.Ast; -using XamlX.IL; using XamlX.TypeSystem; #nullable enable @@ -8,24 +7,23 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; internal class XamlDocumentResource : IXamlDocumentResource { + private readonly Func _createTypeBuilderProvider; + private XamlDocumentTypeBuilderProvider? _typeBuilderProvider; + public XamlDocumentResource( XamlDocument xamlDocument, string? uri, IFileSource? fileSource, IXamlType? classType, bool isPublic, - IXamlTypeBuilder typeBuilder, - IXamlMethodBuilder populateMethod, - IXamlMethodBuilder? buildMethod) + Func createTypeBuilderProvider) { + _createTypeBuilderProvider = createTypeBuilderProvider; XamlDocument = xamlDocument; Uri = uri; FileSource = fileSource; ClassType = classType; IsPublic = isPublic; - TypeBuilder = typeBuilder; - PopulateMethod = populateMethod; - BuildMethod = buildMethod; } public XamlDocument XamlDocument { get; } @@ -34,10 +32,22 @@ internal class XamlDocumentResource : IXamlDocumentResource public IXamlType? ClassType { get; } public bool IsPublic { get; } - public IXamlTypeBuilder TypeBuilder { get; } - public IXamlMethodBuilder PopulateMethod { get; } - public IXamlMethodBuilder? BuildMethod { get; } + public XamlDocumentUsage Usage { get; set; } + + public XamlDocumentTypeBuilderProvider TypeBuilderProvider + { + get + { + if (_typeBuilderProvider is null) + { + _typeBuilderProvider = _createTypeBuilderProvider(); + Usage = XamlDocumentUsage.Used; + } + + return _typeBuilderProvider; + } + } - IXamlMethod? IXamlDocumentResource.BuildMethod => BuildMethod; - IXamlMethod IXamlDocumentResource.PopulateMethod => PopulateMethod; + IXamlMethod? IXamlDocumentResource.BuildMethod => TypeBuilderProvider.BuildMethod; + IXamlMethod IXamlDocumentResource.PopulateMethod => TypeBuilderProvider.PopulateMethod; } diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs new file mode 100644 index 0000000000..4701403fb9 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentTypeBuilderProvider.cs @@ -0,0 +1,23 @@ +#nullable enable + +using XamlX.IL; +using XamlX.TypeSystem; + +namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; + +internal sealed class XamlDocumentTypeBuilderProvider +{ + public XamlDocumentTypeBuilderProvider( + IXamlTypeBuilder typeBuilder, + IXamlMethodBuilder populateMethod, + IXamlMethodBuilder? buildMethod) + { + TypeBuilder = typeBuilder; + PopulateMethod = populateMethod; + BuildMethod = buildMethod; + } + + public IXamlTypeBuilder TypeBuilder { get; } + public IXamlMethodBuilder PopulateMethod { get; } + public IXamlMethodBuilder? BuildMethod { get; } +} diff --git a/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs new file mode 100644 index 0000000000..ec5b931548 --- /dev/null +++ b/src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/XamlDocumentUsage.cs @@ -0,0 +1,8 @@ +namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions; + +internal enum XamlDocumentUsage +{ + Unknown, + Merged, + Used +} diff --git a/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs b/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs index e207bc23ab..85cab1d18e 100644 --- a/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs +++ b/src/Windows/Avalonia.Win32/OpenGl/WglDisplay.cs @@ -38,12 +38,10 @@ namespace Avalonia.Win32.OpenGl [MemberNotNullWhen(true, nameof(s_wglChoosePixelFormatArb))] [MemberNotNullWhen(true, nameof(s_wglCreateContextAttribsArb))] - [MemberNotNullWhen(true, nameof(s_glDebugMessageCallback))] private static bool Initialize() => _initialized ??= InitializeCore(); [MemberNotNullWhen(true, nameof(s_wglChoosePixelFormatArb))] [MemberNotNullWhen(true, nameof(s_wglCreateContextAttribsArb))] - [MemberNotNullWhen(true, nameof(s_glDebugMessageCallback))] private static bool InitializeCore() { Dispatcher.UIThread.VerifyAccess(); @@ -74,9 +72,9 @@ namespace Avalonia.Win32.OpenGl Marshal.GetDelegateForFunctionPointer( wglGetProcAddress("wglChoosePixelFormatARB")); - s_glDebugMessageCallback = - Marshal.GetDelegateForFunctionPointer( - wglGetProcAddress("glDebugMessageCallback")); + s_glDebugMessageCallback = wglGetProcAddress("glDebugMessageCallback") is { } setDebugCallback && setDebugCallback != default ? + Marshal.GetDelegateForFunctionPointer(setDebugCallback) : + null; var formats = new int[1]; @@ -144,8 +142,12 @@ namespace Avalonia.Win32.OpenGl }); } - using(new WglRestoreContext(dc, context, null)) - s_glDebugMessageCallback(Marshal.GetFunctionPointerForDelegate(_debugCallback), IntPtr.Zero); + if (s_glDebugMessageCallback is not null) + { + using (new WglRestoreContext(dc, context, null)) + s_glDebugMessageCallback(Marshal.GetFunctionPointerForDelegate(_debugCallback), IntPtr.Zero); + } + if (context != IntPtr.Zero) return new WglContext(shareContext, version, context, window, dc, _defaultPixelFormat, _defaultPfd); diff --git a/src/Windows/Avalonia.Win32/Win32GlManager.cs b/src/Windows/Avalonia.Win32/Win32GlManager.cs index b3760a37e1..ebb708f4c5 100644 --- a/src/Windows/Avalonia.Win32/Win32GlManager.cs +++ b/src/Windows/Avalonia.Win32/Win32GlManager.cs @@ -20,6 +20,10 @@ static class Win32GlManager { AvaloniaLocator.CurrentMutable.Bind().ToConstant(gl); } + if (gl is IPlatformGraphicsOpenGlContextFactory openGlFactory) + { + AvaloniaLocator.CurrentMutable.Bind().ToConstant(openGlFactory); + } return gl; } diff --git a/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameGenerator.cs b/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameGenerator.cs index 8d45afafa7..fa20be721c 100644 --- a/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameGenerator.cs +++ b/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameGenerator.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Threading; using Avalonia.Generators.Common.Domain; using Microsoft.CodeAnalysis; @@ -31,7 +32,7 @@ internal class AvaloniaNameGenerator : INameGenerator _code = code; } - public IReadOnlyList GenerateNameReferences(IEnumerable additionalFiles) + public IEnumerable GenerateNameReferences(IEnumerable additionalFiles, CancellationToken cancellationToken) { var resolveViews = from file in additionalFiles @@ -39,7 +40,8 @@ internal class AvaloniaNameGenerator : INameGenerator file.Path.EndsWith(".paml") || file.Path.EndsWith(".axaml")) && _pathPattern.Matches(file.Path) - let xaml = file.GetText()!.ToString() + let xaml = file.GetText(cancellationToken)?.ToString() + where xaml != null let view = _classes.ResolveView(xaml) where view != null && _namespacePattern.Matches(view.Namespace) select view; @@ -51,7 +53,7 @@ internal class AvaloniaNameGenerator : INameGenerator let fileName = ResolveViewFileName(view, _naming) select new GeneratedPartialClass(fileName, code); - return query.ToList(); + return query; } private static string ResolveViewFileName(ResolvedView view, ViewFileNamingStrategy strategy) => strategy switch diff --git a/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameSourceGenerator.cs b/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameSourceGenerator.cs index fa1dcde064..407cf4f35f 100644 --- a/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameSourceGenerator.cs +++ b/src/tools/Avalonia.Generators/NameGenerator/AvaloniaNameSourceGenerator.cs @@ -22,8 +22,19 @@ public class AvaloniaNameSourceGenerator : ISourceGenerator return; } - var partials = generator.GenerateNameReferences(context.AdditionalFiles); - foreach (var (fileName, content) in partials) context.AddSource(fileName, content); + var partials = generator.GenerateNameReferences(context.AdditionalFiles, context.CancellationToken); + foreach (var (fileName, content) in partials) + { + if(context.CancellationToken.IsCancellationRequested) + { + break; + } + + context.AddSource(fileName, content); + } + } + catch (OperationCanceledException) + { } catch (Exception exception) { diff --git a/src/tools/Avalonia.Generators/NameGenerator/INameGenerator.cs b/src/tools/Avalonia.Generators/NameGenerator/INameGenerator.cs index 922d800332..5b44de43c1 100644 --- a/src/tools/Avalonia.Generators/NameGenerator/INameGenerator.cs +++ b/src/tools/Avalonia.Generators/NameGenerator/INameGenerator.cs @@ -1,11 +1,12 @@ using System.Collections.Generic; +using System.Threading; using Microsoft.CodeAnalysis; namespace Avalonia.Generators.NameGenerator; internal interface INameGenerator { - IReadOnlyList GenerateNameReferences(IEnumerable additionalFiles); + IEnumerable GenerateNameReferences(IEnumerable additionalFiles, CancellationToken cancellationToken); } internal record GeneratedPartialClass(string FileName, string Content); diff --git a/tests/Avalonia.Base.UnitTests/Utilities/InlineDictionaryTests.cs b/tests/Avalonia.Base.UnitTests/Utilities/InlineDictionaryTests.cs new file mode 100644 index 0000000000..af47d2726a --- /dev/null +++ b/tests/Avalonia.Base.UnitTests/Utilities/InlineDictionaryTests.cs @@ -0,0 +1,53 @@ +#nullable enable + +using System.Collections.Generic; +using Avalonia.Utilities; +using Xunit; + +namespace Avalonia.Base.UnitTests.Utilities; + +public class InlineDictionaryTests +{ + [Fact] + public void Enumeration_After_Add_With_Internal_Array_Works() + { + var dic = new InlineDictionary(); + dic.Add("foo", 1); + dic.Add("bar", 2); + dic.Add("baz", 3); + + Assert.Equal( + new[] { + new KeyValuePair("foo", 1), + new KeyValuePair("bar", 2), + new KeyValuePair("baz", 3) + }, + dic); + } + + [Fact] + public void Enumeration_After_Remove_With_Internal_Array_Works() + { + var dic = new InlineDictionary(); + dic.Add("foo", 1); + dic.Add("bar", 2); + dic.Add("baz", 3); + + Assert.Equal( + new[] { + new KeyValuePair("foo", 1), + new KeyValuePair("bar", 2), + new KeyValuePair("baz", 3) + }, + dic); + + dic.Remove("bar"); + + Assert.Equal( + new[] { + new KeyValuePair("foo", 1), + new KeyValuePair("baz", 3) + }, + dic); + } +} diff --git a/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs b/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs index acae583b5c..f31df71c0d 100644 --- a/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs +++ b/tests/Avalonia.Controls.UnitTests/AutoCompleteBoxTests.cs @@ -1,21 +1,15 @@ using System; -using System.Collections; using System.Collections.Generic; -using System.ComponentModel; using System.Linq; using Avalonia.Controls.Primitives; -using Avalonia.Controls.Presenters; using Avalonia.Controls.Templates; using Avalonia.Data; -using Avalonia.Markup.Data; -using Avalonia.Platform; using Avalonia.Threading; using Avalonia.UnitTests; -using Moq; using Xunit; using System.Collections.ObjectModel; -using System.Reactive.Linq; using System.Reactive.Subjects; +using Avalonia.Input; namespace Avalonia.Controls.UnitTests { @@ -439,6 +433,29 @@ namespace Avalonia.Controls.UnitTests }); } + [Fact] + public void Explicit_Dropdown_Open_Request_MinimumPrefixLength_0() + { + RunTest((control, textbox) => + { + control.Text = ""; + control.MinimumPrefixLength = 0; + Dispatcher.UIThread.RunJobs(); + + Assert.False(control.IsDropDownOpen); + + control.RaiseEvent(new KeyEventArgs + { + RoutedEvent = InputElement.KeyDownEvent, + Key = Key.Down + }); + + Dispatcher.UIThread.RunJobs(); + + Assert.True(control.IsDropDownOpen); + }); + } + /// /// Retrieves a defined predicate filter through a new AutoCompleteBox /// control instance. @@ -1072,14 +1089,14 @@ namespace Avalonia.Controls.UnitTests private AutoCompleteBox CreateControl() { - var datePicker = + var autoCompleteBox = new AutoCompleteBox { Template = CreateTemplate() }; - datePicker.ApplyTemplate(); - return datePicker; + autoCompleteBox.ApplyTemplate(); + return autoCompleteBox; } private TextBox GetTextBox(AutoCompleteBox control) { diff --git a/tests/Avalonia.UnitTests/TestRoot.cs b/tests/Avalonia.UnitTests/TestRoot.cs index fcfd845602..f62afaf74d 100644 --- a/tests/Avalonia.UnitTests/TestRoot.cs +++ b/tests/Avalonia.UnitTests/TestRoot.cs @@ -35,7 +35,6 @@ namespace Avalonia.UnitTests public TestRoot(Control child) : this(false, child) { - Child = child; } public TestRoot(bool useGlobalStyles, Control child)