diff --git a/Documentation/api-filter.yml b/Documentation/api-filter.yml index 41aa629..ddfd856 100644 --- a/Documentation/api-filter.yml +++ b/Documentation/api-filter.yml @@ -15,6 +15,9 @@ apiRules: - exclude: uidRegex: ^ActiproSoftware\.Licensing type: Namespace +- exclude: + uidRegex: ^ActiproSoftware\.Tests + type: Namespace - exclude: uidRegex: ^ActiproSoftware\..*\.Internal type: Namespace diff --git a/Documentation/topics/shared/media.md b/Documentation/topics/shared/media.md index 4fda58e..e4da240 100644 --- a/Documentation/topics/shared/media.md +++ b/Documentation/topics/shared/media.md @@ -5,29 +5,37 @@ order: 9 --- # Media -The [ActiproSoftware.UI.Avalonia.Media](xref:@ActiproUIRoot.Media) namespace defines a [UIColor](xref:@ActiproUIRoot.Media.UIColor) structure for working with colors. +The [ActiproSoftware.UI.Avalonia.Media](xref:@ActiproUIRoot.Media) namespace defines a [UIColor](xref:@ActiproUIRoot.Media.UIColor) structure for working with colors and an extension method to easily convert `Avalonia.Media.Color` to a [UIColor](xref:@ActiproUIRoot.Media.UIColor). ## UIColor Structure -The [UIColor](xref:@ActiproUIRoot.Media.UIColor) structure provides an enhanced representation of a color that supports the RGB, HSL, and HSV color models, conversion between models, and numerous other helper methods. Static methods on the structure are used to create instances of the structure based on the supported models. +The [UIColor](xref:@ActiproUIRoot.Media.UIColor) structure provides an enhanced representation of a color that supports the RGB, HSL, HSV, OKLAB, and OKLCH color models, conversion between models, and numerous other helper methods. Static methods on the structure are used to create instances of the structure based on the supported models. These instance members are found in the structure: | Member | Description | |-----|-----| -| [Alpha](xref:@ActiproUIRoot.Media.UIColor.Alpha) Property | Gets or sets the alpha component of the color, which is a percentage value in the range `0.0` to `1.0`. | -| [HslHue](xref:@ActiproUIRoot.Media.UIColor.HslHue) Property | Gets or sets the HSL hue component of the color, which is a color wheel degree value in the range `0` to `360`. | -| [HslLightness](xref:@ActiproUIRoot.Media.UIColor.HslLightness) Property | Gets or sets the HSL lightness component of the color, which is a percentage value in the range `0.0` to `1.0`. | -| [HslSaturation](xref:@ActiproUIRoot.Media.UIColor.HslSaturation) Property | Gets or sets the HSL saturation component of the color, which is a percentage value in the range `0.0` to `1.0`. | -| [HsvHue](xref:@ActiproUIRoot.Media.UIColor.HsvHue) Property | Gets or sets the HSV hue component of the color, which is a percentage value in the range `0.0` to `1.0`. | -| [HsvSaturation](xref:@ActiproUIRoot.Media.UIColor.HsvSaturation) Property | Gets or sets the HSV saturation component of the color, which is a percentage value in the range `0.0` to `1.0`. | -| [HsvValue](xref:@ActiproUIRoot.Media.UIColor.HsvValue) Property | Gets or sets the HSV value (brightness) component of the color, which is a percentage value in the range `0.0` to `1.0`. | +| [Alpha](xref:@ActiproUIRoot.Media.UIColor.Alpha) Property | The alpha component of the color, which is a percentage value in the range `0.0` to `1.0`. | +| [HslHue](xref:@ActiproUIRoot.Media.UIColor.HslHue) Property | The HSL hue component of the color, which is a color wheel degree value in the range `0` to `360`. | +| [HslLightness](xref:@ActiproUIRoot.Media.UIColor.HslLightness) Property | The HSL lightness component of the color, which is a percentage value in the range `0.0` to `1.0`. | +| [HslSaturation](xref:@ActiproUIRoot.Media.UIColor.HslSaturation) Property | The HSL saturation component of the color, which is a percentage value in the range `0.0` to `1.0`. | +| [HsvHue](xref:@ActiproUIRoot.Media.UIColor.HsvHue) Property | The HSV hue component of the color, which is a percentage value in the range `0.0` to `1.0`. | +| [HsvSaturation](xref:@ActiproUIRoot.Media.UIColor.HsvSaturation) Property | The HSV saturation component of the color, which is a percentage value in the range `0.0` to `1.0`. | +| [HsvValue](xref:@ActiproUIRoot.Media.UIColor.HsvValue) Property | The HSV value (brightness) component of the color, which is a percentage value in the range `0.0` to `1.0`. | | [IsDark](xref:@ActiproUIRoot.Media.UIColor.IsDark) Property | Gets whether the color is a dark color. | | [IsLight](xref:@ActiproUIRoot.Media.UIColor.IsLight) Property | Gets whether the color is a light color. | -| [RbgAlpha](xref:@ActiproUIRoot.Media.UIColor.RgbAlpha) Property | Gets or sets the RGB alpha component of the color, which is a byte value in the range `0` to `255`. | -| [RbgBlue](xref:@ActiproUIRoot.Media.UIColor.RgbBlue) Property | Gets or sets the RGB blue component of the color, which is a byte value in the range `0` to `255`. | -| [RbgGreen](xref:@ActiproUIRoot.Media.UIColor.RgbGreen) Property | Gets or sets the RGB green component of the color, which is a byte value in the range `0` to `255`. | -| [RbgRed](xref:@ActiproUIRoot.Media.UIColor.RgbRed) Property | Gets or sets the RGB red component of the color, which is a byte value in the range `0` to `255`. | +| [OklabAChromaticity](xref:@ActiproUIRoot.Media.UIColor.OklabAChromaticity) Property | The OKLAB A chromaticity component of the color, which is a value in the range `-0.4`..`0.4`. | +| [OklabBChromaticity](xref:@ActiproUIRoot.Media.UIColor.OklabBChromaticity) Property | The OKLAB B chromaticity component of the color, which is a value in the range `-0.4`..`0.4`. | +| [OklabLightness](xref:@ActiproUIRoot.Media.UIColor.OklabLightness) Property | The OKLAB lightness component of the color, which is a percentage value in the range `0.0` to `1.0`. | +| [OklchChroma](xref:@ActiproUIRoot.Media.UIColor.OklchChroma) Property | The OKLCH chroma (saturation) component of the color, which is a value in the range `0.0`..`0.4`. | +| [OklchHue](xref:@ActiproUIRoot.Media.UIColor.OklchHue) Property | The OKLCH hue component of the color, which is a color wheel degree value in the range `0`..`360`. | +| [OklchLightness](xref:@ActiproUIRoot.Media.UIColor.OklchLightness) Property | The OKLCH lightness component of the color, which is a percentage value in the range `0.0` to `1.0`. | +| [RbgAlpha](xref:@ActiproUIRoot.Media.UIColor.RgbAlpha) Property | The RGB alpha component of the color, which is a byte value in the range `0` to `255`. | +| [RbgBlue](xref:@ActiproUIRoot.Media.UIColor.RgbBlue) Property | The RGB blue component of the color, which is a byte value in the range `0` to `255`. | +| [RbgGreen](xref:@ActiproUIRoot.Media.UIColor.RgbGreen) Property | The RGB green component of the color, which is a byte value in the range `0` to `255`. | +| [RbgRed](xref:@ActiproUIRoot.Media.UIColor.RgbRed) Property | The RGB red component of the color, which is a byte value in the range `0` to `255`. | +| [ToChromaticAdaptation](xref:@ActiproUIRoot.Media.UIColor.ToChromaticAdaptation*) Method | Uses chromatic adaptation to create a new [UIColor](xref:@ActiproUIRoot.Media.UIColor) that renders clearly on the specified background color. Chromatic adaptation is commonly used to adapt a color that was intended for use with light backgrounds to render properly on dark backgrounds. | +| [ToGrayscale](xref:@ActiproUIRoot.Media.UIColor.ToGrayscale*) Method | Creates a new [UIColor](xref:@ActiproUIRoot.Media.UIColor) that is a grayscale transformation of the specified color. | | [ToHexString](xref:@ActiproUIRoot.Media.UIColor.ToHexString*) Method | Converts the color value to an RGB hexadecimal string (e.g., `"#ff00ff"`, `"#80ff00ff"`). | | [ToHsl](xref:@ActiproUIRoot.Media.UIColor.ToHsl*) Method | Converts the color value to an `HslColor` instance that represents the color in the HSL (hue, saturation, and lightness) color model. | | [ToHsv](xref:@ActiproUIRoot.Media.UIColor.ToHsv*) Method | Converts the color value to an `HsvColor` instance that represents the color in the HSV (hue, saturation, and value) color model. | @@ -40,9 +48,25 @@ These static members are found in the structure: | Member | Description | |-----|-----| -| [FromHsl](xref:@ActiproUIRoot.Media.UIColor.FromHsl*) Method | Creates a `UIColor` instance from the specified HSL (hue, saturation, lightness, and optional alpha) components or `HslColor` instance. | -| [FromHsv](xref:@ActiproUIRoot.Media.UIColor.FromHsv*) Method | Creates a `UIColor` instance from the specified HSV (hue, saturation, value, and optional alpha) components or `HsvColor` instance. | +| [FromHsl](xref:@ActiproUIRoot.Media.UIColor.FromHsl*) Method | Creates a `UIColor` instance from the specified HSL (hue, saturation, and lightness) and optional alpha components, or `HslColor` instance. | +| [FromHsv](xref:@ActiproUIRoot.Media.UIColor.FromHsv*) Method | Creates a `UIColor` instance from the specified HSV (hue, saturation, and value) and optional alpha components, or `HsvColor` instance. | | [FromMix](xref:@ActiproUIRoot.Media.UIColor.FromMix*) Method | Creates a `UIColor` instance that is the specified percentage between the value of two `Color` objects. | -| [FromRgb](xref:@ActiproUIRoot.Media.UIColor.FromRgb*) Method | Creates a `UIColor` instance from the specified RGB (red, green, blue, and optional alpha) components or `Color` instance. | +| [FromOklab](xref:@ActiproUIRoot.Media.UIColor.FromOklab*) Method | Creates a `UIColor` instance from the specified OKLAB (lightness, A, and B) and optional alpha components. | +| [FromOklch](xref:@ActiproUIRoot.Media.UIColor.FromOklch*) Method | Creates a `UIColor` instance from the specified OKLCH (lightness, chroma, and hue) and optional alpha components. | +| [FromRgb](xref:@ActiproUIRoot.Media.UIColor.FromRgb*) Method | Creates a `UIColor` instance from the specified RGB (red, green, and blue) and optional alpha components, or `Color` instance. | | [Parse](xref:@ActiproUIRoot.Media.UIColor.Parse*) Method | Creates a `UIColor` instance from the specified color name, RGB hexadecimal string, or any other color string supported by `Color.Parse`. | -| [TryParse](xref:@ActiproUIRoot.Media.UIColor.Parse*) Method | Tries to creates a `UIColor` instance from the specified color name, RGB hexadecimal string, or any other color string supported by `Color.Parse`. | \ No newline at end of file +| [TryParse](xref:@ActiproUIRoot.Media.UIColor.Parse*) Method | Tries to creates a `UIColor` instance from the specified color name, RGB hexadecimal string, or any other color string supported by `Color.Parse`. | + +> [!TIP] +> [UIColor](xref:@ActiproUIRoot.Media.UIColor) defines several implicit cast overloads to easily convert to/from [UIColor](xref:@ActiproUIRoot.Media.UIColor) and the Avalonia types for `Color`, `HslColor`, and `HsvColor`. + +## Color Extensions + +The following extension methods to `Avalonia.Media.Color` are defined on [ColorExtensions](xref:@ActiproUIRoot.Media.ColorExtensions): + +| Member | Description | +|-----|-----| +| [ToUIColor](xref:@ActiproUIRoot.Media.ColorExtensions.ToUIColor*) Method | Creates a new [UIColor](xref:@ActiproUIRoot.Media.UIColor) initialized from the `Color` for easily accessing the additional capabilities of [UIColor](xref:@ActiproUIRoot.Media.UIColor). | + +> [!IMPORTANT] +> The [ActiproSoftware.UI.Avalonia.Media](xref:@ActiproUIRoot.Media) namespace must be imported with a `using` statement to access the extensions. \ No newline at end of file diff --git a/Documentation/topics/themes/getting-started.md b/Documentation/topics/themes/getting-started.md index 37c4043..cc11ba0 100644 --- a/Documentation/topics/themes/getting-started.md +++ b/Documentation/topics/themes/getting-started.md @@ -174,6 +174,9 @@ When using all controls: ``` +> [!WARNING] +> The `ModernTheme.Includes` property dynamically includes `Styles` instances that apply control themes for various product assemblies. While this simplifies the Application XAML, it can lead to a runtime exception when executing an application that uses the `PublishAot` project setting for Native AOT (Ahead-of-Time) support and hasn't been published with `dotnet publish` or an IDE's equivalent publish feature. See the [Troubleshooting](../troubleshooting.md) topic for details on how to statically include appropriate `Styles` instances, avoiding AOT errors. + ### Native Control Themes Setting Native Avalonia controls must have themes applied or else an application window will render without most or all content being visible. Avalonia ships with the *Simple* and *Fluent* themes as built-in options. Actipro's theme also defines control themes for all native Avalonia controls and can be used in place of the *Simple*, *Fluent*, or other themes. diff --git a/Documentation/topics/themes/native-control-themes.md b/Documentation/topics/themes/native-control-themes.md index d9c5916..9f876a2 100644 --- a/Documentation/topics/themes/native-control-themes.md +++ b/Documentation/topics/themes/native-control-themes.md @@ -183,6 +183,8 @@ These style class names trigger special behaviors: - [ButtonSpinnerOutline](xref:@ActiproUIRoot.Themes.ControlThemeKind.ButtonSpinnerOutline) (`theme-outline`) - Has an outline appearance. - [ButtonSpinnerSoft](xref:@ActiproUIRoot.Themes.ControlThemeKind.ButtonSpinnerSoft) (`theme-soft`) - Has a soft fill appearance. +Set the [ThemeProperties](xref:@ActiproUIRoot.Themes.ThemeProperties).[SpinnerHasHorizontalOrientation](xref:@ActiproUIRoot.Themes.ThemeProperties.SpinnerHasHorizontalOrientationProperty) attached property on a `ButtonSpinner` to `true` to arrange spinner buttons horizontally instead of vertically. Horizontal arrangement is better for touch-friendly user interfaces since each button gets twice the amount of surface area. [Theme Definitions](theme-definitions.md) also provide a global default value for this attached property that can be altered. + The following additional control theme is available for the `Button` used by the default control theme: - [SpinnerButton](xref:@ActiproUIRoot.Themes.ControlThemeKind.SpinnerButton) @@ -243,6 +245,8 @@ The following additional control theme is used by the default control theme: - [NumericUpDownOutline](xref:@ActiproUIRoot.Themes.ControlThemeKind.NumericUpDownOutline) (`theme-outline`) - Has an outline appearance. - [NumericUpDownSoft](xref:@ActiproUIRoot.Themes.ControlThemeKind.NumericUpDownSoft) (`theme-soft`) - Has a soft fill appearance. +Set the [ThemeProperties](xref:@ActiproUIRoot.Themes.ThemeProperties).[SpinnerHasHorizontalOrientation](xref:@ActiproUIRoot.Themes.ThemeProperties.SpinnerHasHorizontalOrientationProperty) attached property on a `NumericUpDown` to `true` to arrange spinner buttons horizontally instead of vertically. Horizontal arrangement is better for touch-friendly user interfaces since each button gets twice the amount of surface area. [Theme Definitions](theme-definitions.md) also provide a global default value for this attached property that can be altered. + #### TextBox Type ![Screenshot](images/text-box-themes.png) diff --git a/Documentation/topics/themes/theme-definitions.md b/Documentation/topics/themes/theme-definitions.md index ce6bb4b..bc2c8eb 100644 --- a/Documentation/topics/themes/theme-definitions.md +++ b/Documentation/topics/themes/theme-definitions.md @@ -85,6 +85,7 @@ Color ramp name properties should be set to [Hue](xref:@ActiproUIRoot.Themes.Gen |-----|-----| | [ButtonAppearanceKind](xref:@ActiproUIRoot.Themes.Generation.ThemeDefinition.ButtonAppearanceKind) | The [ButtonAppearanceKind](xref:@ActiproUIRoot.Themes.Generation.ButtonAppearanceKind) that indicates the default appearance for various button controls (e.g., `Button`, `SplitButton`). | | [EditAppearanceKind](xref:@ActiproUIRoot.Themes.Generation.ThemeDefinition.EditAppearanceKind) | The [EditAppearanceKind](xref:@ActiproUIRoot.Themes.Generation.EditAppearanceKind) that indicates the default appearance for various edit controls (e.g., `ComboBox`, `TextBox`). | +| [SpinnerHasHorizontalOrientation](xref:@ActiproUIRoot.Themes.Generation.ThemeDefinition.SpinnerHasHorizontalOrientation) | Whether to arrange `ButtonSpinner` buttons horizontally. | [TabAppearanceKind](xref:@ActiproUIRoot.Themes.Generation.ThemeDefinition.TabAppearanceKind) | The [TabAppearanceKind](xref:@ActiproUIRoot.Themes.Generation.TabAppearanceKind) that indicates the default appearance for various tab controls (e.g., `TabControl`). | ## Custom Theme Generators diff --git a/Documentation/topics/themes/user-interface-density.md b/Documentation/topics/themes/user-interface-density.md index 06a0d03..3d89e91 100644 --- a/Documentation/topics/themes/user-interface-density.md +++ b/Documentation/topics/themes/user-interface-density.md @@ -74,6 +74,9 @@ if (ModernTheme.TryGetCurrent(out var modernTheme) && (modernTheme.Definition is _ => 14.0, // Normal, Spacious }; + // Arrange spinner buttons horizontally in Spacious density + definition.SpinnerHasHorizontalOrientation = (density == UserInterfaceDensity.Spacious); + // Set the new UI density modernTheme.Definition.UserInterfaceDensity = newDensity; diff --git a/Documentation/topics/troubleshooting.md b/Documentation/topics/troubleshooting.md index 0220d77..7490762 100644 --- a/Documentation/topics/troubleshooting.md +++ b/Documentation/topics/troubleshooting.md @@ -42,6 +42,46 @@ It is very important to note that the data binding errors are NOT problems in ou So just to reiterate, the data binding error messages are not problems with our code, and are simple warnings due to data bindings trying to resolve themselves before the targets' visual trees are created. You may safely ignore these error messages. +## Native AOT (Ahead-of-Time) Generates "No precompiled XAML found for avares:..." Error in Debugger + +Applications that want to take advantage of Native AOT add the `true` setting to their project's properties. Adding this setting can lead to a runtime exception when executing the application if it hasn't been published with `dotnet publish` or an IDE's equivalent publish feature. This setting also enables trimming, which will attempt to remove unused code from the compiled application. Proper trimming requires the compiler to know which code is actually in use, and then can cause problems with dynamic code that cannot be statically analyzed. + +The [ModernTheme](xref:@ActiproUIRoot.Themes.ModernTheme) class used to enable [Actipro Themes](themes/getting-started.md) dynamically loads additional theme assets from other assemblies based on the value of the [Includes](xref:@ActiproUIRoot.Themes.ModernTheme.Includes) property. While the class has been properly attributed to indicate its dependency on other assemblies and can be successfully published, compiled applications with `PublishAot` set to `true` that didn't also get published appear to have issues with the dynamic dependencies and will trim the theme resources anyway. This can result in an error message like the following when the `ModernTheme` is loaded within `Application.Styles`: + +``` +No precompiled XAML found for avares://ActiproSoftware.Avalonia.Fundamentals/Themes/Common.axaml (baseUri: ), make sure to specify x:Class and include your XAML file as AvaloniaResource +``` + +To resolve the issue, the application will need to explicitly reference the necessary styles to prevent them from being trimmed. The following shows how to redefine `ModernTheme` to explicitly include all the possible style resources: + +```xml + + + ... + + + + + + + + + + + + + + + + +``` + +Basically, whichever resource was mentioned by the error message will need to be explicitly listed like shown above. + +The [ModernTheme](xref:@ActiproUIRoot.Themes.ModernTheme).[Includes](xref:@ActiproUIRoot.Themes.ModernTheme.Includes) property does not have to be defined when explicitly including the styles, and you should only include styles for the assemblies used by your application. + ## WebAssembly (WASM) Performance Issues Avalonia UI supports running in the browser with WebAssembly. As of v11.0, the Avalonia UI framework documention is clear to indicate the functionality is not ready for production. During testing with Actipro Avalonia UI controls in a browser, you may notice less-than-desired performance compared to running natively. This is expected to improve with .NET 8. \ No newline at end of file diff --git a/Samples/SampleBrowser/Directory.Build.props b/Samples/SampleBrowser/Directory.Build.props index b906b3a..4a62a9e 100644 --- a/Samples/SampleBrowser/Directory.Build.props +++ b/Samples/SampleBrowser/Directory.Build.props @@ -7,8 +7,8 @@ enable true - 23.1.1.0 - 23.1.0.0 - 20231114 + 23.1.2.0 + 23.1.0.0 - 20231204 Actipro Avalonia UI Controls Sample Browser $(Product) @@ -25,5 +25,10 @@ false - + + + + + + \ No newline at end of file diff --git a/Samples/SampleBrowser/References/ActiproSoftware.References.props b/Samples/SampleBrowser/References/ActiproSoftware.References.props index 3136e20..9c2f34c 100644 --- a/Samples/SampleBrowser/References/ActiproSoftware.References.props +++ b/Samples/SampleBrowser/References/ActiproSoftware.References.props @@ -2,7 +2,7 @@ - 23.1.1 + 23.1.2 diff --git a/Samples/SampleBrowser/SampleBrowser.Common/ProductSamples/ThemesSamples/NativeControls/ButtonSpinnerSamples.axaml b/Samples/SampleBrowser/SampleBrowser.Common/ProductSamples/ThemesSamples/NativeControls/ButtonSpinnerSamples.axaml index 5966aaa..5b8210f 100644 --- a/Samples/SampleBrowser/SampleBrowser.Common/ProductSamples/ThemesSamples/NativeControls/ButtonSpinnerSamples.axaml +++ b/Samples/SampleBrowser/SampleBrowser.Common/ProductSamples/ThemesSamples/NativeControls/ButtonSpinnerSamples.axaml @@ -57,6 +57,7 @@ Show buttons + Horizontal buttons Allow spin Enabled @@ -64,7 +65,7 @@ + ]]> @@ -84,6 +85,9 @@ + diff --git a/Samples/SampleBrowser/SampleBrowser.Common/ProductSamples/ThemesSamples/NativeControls/NumericUpDownSamples.axaml b/Samples/SampleBrowser/SampleBrowser.Common/ProductSamples/ThemesSamples/NativeControls/NumericUpDownSamples.axaml index 0977f3b..16945fb 100644 --- a/Samples/SampleBrowser/SampleBrowser.Common/ProductSamples/ThemesSamples/NativeControls/NumericUpDownSamples.axaml +++ b/Samples/SampleBrowser/SampleBrowser.Common/ProductSamples/ThemesSamples/NativeControls/NumericUpDownSamples.axaml @@ -31,9 +31,9 @@ > Show buttons + Horizontal buttons Allow spin Enabled Read-only @@ -65,7 +66,7 @@ + ]]> + diff --git a/Samples/SampleBrowser/SampleBrowser.Common/ProductSamples/ThemesSamples/NativeControls/RadioButtonSamples.axaml b/Samples/SampleBrowser/SampleBrowser.Common/ProductSamples/ThemesSamples/NativeControls/RadioButtonSamples.axaml index e2facb4..1352530 100644 --- a/Samples/SampleBrowser/SampleBrowser.Common/ProductSamples/ThemesSamples/NativeControls/RadioButtonSamples.axaml +++ b/Samples/SampleBrowser/SampleBrowser.Common/ProductSamples/ThemesSamples/NativeControls/RadioButtonSamples.axaml @@ -76,7 +76,7 @@ - + true false diff --git a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser.Common.csproj b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser.Common.csproj index 19ca4d5..34dd546 100644 --- a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser.Common.csproj +++ b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser.Common.csproj @@ -2,7 +2,7 @@ SampleBrowser - + $(DefineConstants);MS_LOGGING - + diff --git a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/App.axaml b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/App.axaml index 11ca58e..8876ba7 100644 --- a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/App.axaml +++ b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/App.axaml @@ -38,7 +38,7 @@ --> - + diff --git a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Controls/ImageLoader.cs b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Controls/ImageLoader.cs index b27d56d..1e99106 100644 --- a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Controls/ImageLoader.cs +++ b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Controls/ImageLoader.cs @@ -3,6 +3,7 @@ using Avalonia.Media.Imaging; using Avalonia.Platform; using System; +using System.Diagnostics.CodeAnalysis; using System.Reflection; namespace ActiproSoftware.SampleBrowser { @@ -21,6 +22,7 @@ public static class ImageLoader { /// /// The path of the resource file relative to the Images folder. /// An . + [UnconditionalSuppressMessage("Aot", "IL2026:Requires unreferenced code", Justification = "Only local resources are loaded with AvaloniaXamlLoader and this assembly, by design, should not be trimmed.")] private static IImage? LoadImageResource(string relPath) { if (relPath is null) throw new ArgumentNullException(nameof(relPath)); diff --git a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Documents/ReleaseHistories/v23.1.md b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Documents/ReleaseHistories/v23.1.md index 115b748..3831b19 100644 --- a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Documents/ReleaseHistories/v23.1.md +++ b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Documents/ReleaseHistories/v23.1.md @@ -1,4 +1,24 @@ -# 11/14/2023 - v23.1.1 +# 12/4/2023 - v23.1.2 + +## Themes +- Added the ThemeProperties.SpinnerHasHorizontalOrientation attached property that can arrange ButtonSpinner and NumericUpDown buttons horizontally, making them more touch-friendly. +- Added the ThemeDefinition.SpinnerHasHorizontalOrientation property that provides a global default for the ThemeProperties.SpinnerHasHorizontalOrientation attached property. +- Fixed an issue where the new density-related markup extensions added in the previous build weren't parsing numbers with invariant culture, which had led to excessive padding on some systems. +- Fixed an issue where a menu item's sub-menu could close when the pointer was over the popup's shadow. +## Shared Library +- Added various members to the UIColor structure to support the OKLAB and OKLCH color models. +- Added the UIColor.ToChromaticAdaptation method that updates the color to render clearly on a given background. +- Added the UIColor.ToGrayscale method that updates the color to a grayscale value. +- Added the Color.ToUIColor extension method that converts a Color to a UIColor. +- Added the IOrientedElement interface and numerous extension methods. +- Added the ShadowChrome.Background and Padding properties. +- Updated ArrayExtension and DelimitedArrayExtension to return generic object arrays for AOT compatibility instead of type-specific arrays. The ArrayExtension.Type property has been deprecated and will be removed in a future release. +## All +- Improved support for trimming and Native AOT (Ahead-of-Time). + +--- + +# 11/14/2023 - v23.1.1 ## Themes - Added a new ThemeDefinition.UserInterfaceDensity property with Compact, Normal, and Spacious options that can alter spacing throughout an application's user interface. The default value is Normal, and can be changed in the Sample Browser with new View menu items. diff --git a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Utilities/ColorPalette/ColorPaletteView.axaml b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Utilities/ColorPalette/ColorPaletteView.axaml index d681af5..58f1a5d 100644 --- a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Utilities/ColorPalette/ColorPaletteView.axaml +++ b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Utilities/ColorPalette/ColorPaletteView.axaml @@ -53,9 +53,7 @@ - - - + diff --git a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Utilities/ColorPalette/ColorRampShadeViewModel.cs b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Utilities/ColorPalette/ColorRampShadeViewModel.cs index 45c5ff3..8de1b7b 100644 --- a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Utilities/ColorPalette/ColorRampShadeViewModel.cs +++ b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Utilities/ColorPalette/ColorRampShadeViewModel.cs @@ -1,5 +1,6 @@ using ActiproSoftware.UI.Avalonia.Media; using ActiproSoftware.UI.Avalonia.Themes.Generation; +using Avalonia.Media; namespace ActiproSoftware.SampleBrowser { @@ -17,12 +18,21 @@ public class ColorRampShadeViewModel : ObservableObjectBase { public ColorRampShadeViewModel(ColorRampViewModel colorRamp, ColorRampShade colorRampShade) { ColorRamp = colorRamp; _colorRampShade = colorRampShade; + + // IMPORTANT: When trimming for Native AOT, a template could not bind SolidColorBrush.Color to a + // UIColor because the implicit cast from UIColor to Color was not working. Either had to... + // A) Create an Avalonia.Media.Color property to use for the SolidColorBrush.Color binding, or + // B) Create an IBrush. + // Used option B to avoid confusion of two color-based properties. + Brush = new SolidColorBrush(_colorRampShade.Color); } ///////////////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC PROCEDURES ///////////////////////////////////////////////////////////////////////////////////////////////////// + public IBrush Brush { get; } + public UIColor Color => _colorRampShade.Color; public ColorRampViewModel ColorRamp { get; } diff --git a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Utilities/StringResourceBrowser/StringResourceBrowserViewModel.cs b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Utilities/StringResourceBrowser/StringResourceBrowserViewModel.cs index 014d478..e2815be 100644 --- a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Utilities/StringResourceBrowser/StringResourceBrowserViewModel.cs +++ b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/Utilities/StringResourceBrowser/StringResourceBrowserViewModel.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using AP = ActiproSoftware.Properties; namespace ActiproSoftware.SampleBrowser.Utilities.StringResourceBrowser { @@ -8,10 +10,20 @@ namespace ActiproSoftware.SampleBrowser.Utilities.StringResourceBrowser { /// public class StringResourceBrowserViewModel : ObservableObjectBase { + ///////////////////////////////////////////////////////////////////////////////////////////////////// + // OBJECT + ///////////////////////////////////////////////////////////////////////////////////////////////////// + + [DynamicDependency(DynamicallyAccessedMemberTypes.All, typeof(AP.Shared.SR))] // Required to ensure SR.GetString method is available + public StringResourceBrowserViewModel() { + // Explicitly reference the string resource enum so reflection metadata is not trimmed + _ = Enum.GetValues(); + } + ///////////////////////////////////////////////////////////////////////////////////////////////////// // PUBLIC PROCEDURES ///////////////////////////////////////////////////////////////////////////////////////////////////// - + /// /// The collection of all assemblies with string resources. /// diff --git a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/ViewModels/ApplicationViewModel.cs b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/ViewModels/ApplicationViewModel.cs index 071e5da..1ea2ccd 100644 --- a/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/ViewModels/ApplicationViewModel.cs +++ b/Samples/SampleBrowser/SampleBrowser.Common/SampleBrowser/ViewModels/ApplicationViewModel.cs @@ -6,6 +6,7 @@ using Avalonia.Markup.Xaml; using Avalonia.Media; using System; +using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Windows.Input; @@ -75,6 +76,8 @@ private ApplicationViewModel() { /// /// The element's XAML path. /// The for the specified element's XAML path. + [UnconditionalSuppressMessage("Aot", "IL2026:Requires unreferenced code", Justification = "Only local resources are loaded with AvaloniaXamlLoader and this assembly, by design, should not be trimmed.")] + [UnconditionalSuppressMessage("Aot", "IL2057:Type availability", Justification = "Only local types are created by Activator and this assembly, by design, should not be trimmed.")] private static Control? CreateElement(string? path) { if (!string.IsNullOrEmpty(path)) { // Markdown files display in a DocumentViewer @@ -472,13 +475,19 @@ public ICommand SetUserInterfaceDensityCommand if (density.HasValue && ModernTheme.TryGetCurrent(out var theme)) { var definition = theme.Definition; if (definition is not null) { + // Optionally update the base font size based on the density definition.BaseFontSize = density switch { UserInterfaceDensity.Compact => 13.0, _ => 14.0, // Normal, Spacious }; + + // Arrange spinner buttons horizontally in Spacious density + definition.SpinnerHasHorizontalOrientation = (density == UserInterfaceDensity.Spacious); + // Set the new UI density definition.UserInterfaceDensity = density.Value; + // Must manually refresh resources after changing definition properties theme.RefreshResources(); } } diff --git a/Samples/SampleBrowser/SampleBrowser.Desktop/SampleBrowser.Desktop.csproj b/Samples/SampleBrowser/SampleBrowser.Desktop/SampleBrowser.Desktop.csproj index b0846e5..7f003b3 100644 --- a/Samples/SampleBrowser/SampleBrowser.Desktop/SampleBrowser.Desktop.csproj +++ b/Samples/SampleBrowser/SampleBrowser.Desktop/SampleBrowser.Desktop.csproj @@ -9,7 +9,7 @@ - +