Browse Source

Allow only well known ThemeVariant values in xaml compiler, add more documentation.

pull/8166/head
Max Katz 4 years ago
parent
commit
35662ad4cb
  1. 2
      samples/ControlCatalog/Pages/ThemePage.axaml.cs
  2. 62
      src/Avalonia.Base/Styling/ThemeVariant.cs
  3. 3
      src/Avalonia.Base/Styling/ThemeVariantTypeConverter.cs
  4. 2
      src/Avalonia.Controls/Application.cs
  5. 2
      src/Avalonia.Controls/TopLevel.cs
  6. 7
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs
  7. 2
      src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs
  8. 13
      tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ThemeDictionariesTests.cs

2
samples/ControlCatalog/Pages/ThemePage.axaml.cs

@ -18,7 +18,7 @@ namespace ControlCatalog.Pages
selector.Items = new[]
{
new ThemeVariant("Default"),
ThemeVariant.Default,
ThemeVariant.Dark,
ThemeVariant.Light,
Pink

62
src/Avalonia.Base/Styling/ThemeVariant.cs

@ -5,20 +5,60 @@ using Avalonia.Platform;
namespace Avalonia.Styling;
/// <summary>
/// Specifies a UI theme variant that should be used for the
/// </summary>
[TypeConverter(typeof(ThemeVariantTypeConverter))]
public sealed record ThemeVariant(object Key)
{
public sealed record ThemeVariant
{
/// <summary>
/// Creates a new instance of the <see cref="ThemeVariant"/>
/// </summary>
/// <param name="key">Key of the theme variant by which variants are compared.</param>
/// <param name="inheritVariant">Reference to a theme variant which should be used, if resource wasn't found for the requested variant.</param>
/// <exception cref="ArgumentException">Thrown if inheritVariant is a reference to the <see cref="ThemeVariant.Default"/> which is ambiguous value to inherit.</exception>
/// <exception cref="ArgumentNullException">Thrown if key is null.</exception>
public ThemeVariant(object key, ThemeVariant? inheritVariant)
: this(key)
{
Key = key ?? throw new ArgumentNullException(nameof(key));
InheritVariant = inheritVariant;
if (inheritVariant == Default)
{
throw new ArgumentException("Inheriting default theme variant is not supported.", nameof(inheritVariant));
}
}
private ThemeVariant(object key)
{
Key = key;
}
/// <summary>
/// Key of the theme variant by which variants are compared.
/// </summary>
public object Key { get; }
/// <summary>
/// Reference to a theme variant which should be used, if resource wasn't found for the requested variant.
/// </summary>
public ThemeVariant? InheritVariant { get; }
/// <summary>
/// Inherit theme variant from the parent. If set on Application, system theme is inherited.
/// Using Default as the ResourceDictionary.Key marks this dictionary as a fallback in case the theme variant or resource key is not found in other theme dictionaries.
/// </summary>
public static ThemeVariant Default { get; } = new(nameof(Default));
/// <summary>
/// Use the Light theme variant.
/// </summary>
public static ThemeVariant Light { get; } = new(nameof(Light));
public static ThemeVariant Dark { get; } = new(nameof(Dark));
public ThemeVariant? InheritVariant { get; init; }
/// <summary>
/// Use the Dark theme variant.
/// </summary>
public static ThemeVariant Dark { get; } = new(nameof(Dark));
public override string ToString()
{
@ -35,7 +75,7 @@ public sealed record ThemeVariant(object Key)
return Key == other?.Key;
}
public static ThemeVariant FromPlatformThemeVariant(PlatformThemeVariant themeVariant)
public static explicit operator ThemeVariant(PlatformThemeVariant themeVariant)
{
return themeVariant switch
{
@ -45,19 +85,19 @@ public sealed record ThemeVariant(object Key)
};
}
public PlatformThemeVariant? ToPlatformThemeVariant()
public static explicit operator PlatformThemeVariant?(ThemeVariant themeVariant)
{
if (this == Light)
if (themeVariant == Light)
{
return PlatformThemeVariant.Light;
}
else if (this == Dark)
else if (themeVariant == Dark)
{
return PlatformThemeVariant.Dark;
}
else if (InheritVariant is { } inheritVariant)
else if (themeVariant.InheritVariant is { } inheritVariant)
{
return inheritVariant.ToPlatformThemeVariant();
return (PlatformThemeVariant?)inheritVariant;
}
return null;

3
src/Avalonia.Base/Styling/ThemeVariantTypeConverter.cs

@ -15,9 +15,10 @@ public class ThemeVariantTypeConverter : TypeConverter
{
return value switch
{
nameof(ThemeVariant.Default) => ThemeVariant.Default,
nameof(ThemeVariant.Light) => ThemeVariant.Light,
nameof(ThemeVariant.Dark) => ThemeVariant.Dark,
_ => new ThemeVariant(value)
_ => throw new NotSupportedException("ThemeVariant type converter supports only build in variants. For custom variants please use x:Static markup extension.")
};
}
}

2
src/Avalonia.Controls/Application.cs

@ -340,7 +340,7 @@ namespace Avalonia
private void OnColorValuesChanged(object? sender, PlatformColorValues e)
{
SetValue(ActualThemeVariantProperty, ThemeVariant.FromPlatformThemeVariant(e.ThemeVariant), BindingPriority.Template);
SetValue(ActualThemeVariantProperty, (ThemeVariant)e.ThemeVariant, BindingPriority.Template);
}
}
}

2
src/Avalonia.Controls/TopLevel.cs

@ -435,7 +435,7 @@ namespace Avalonia.Controls
}
else if (change.Property == ActualThemeVariantProperty)
{
PlatformImpl?.SetFrameThemeVariant(change.GetNewValue<ThemeVariant>().ToPlatformThemeVariant() ?? PlatformThemeVariant.Light);
PlatformImpl?.SetFrameThemeVariant((PlatformThemeVariant?)change.GetNewValue<ThemeVariant>() ?? PlatformThemeVariant.Light);
}
}

7
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/AvaloniaXamlIlLanguageParseIntrinsics.cs

@ -302,13 +302,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions
result = new XamlStaticExtensionNode(new XamlAstObjectNode(node, node.Type), themeVariantTypeRef, foundConstProperty.Name);
return true;
}
result = new XamlAstNewClrObjectNode(node, themeVariantTypeRef, types.ThemeVariantConstructor,
new List<IXamlAstValueNode>()
{
new XamlConstantNode(node, context.Configuration.WellKnownTypes.String, variantText)
});
return true;
}
result = null;

2
src/Markup/Avalonia.Markup.Xaml.Loader/CompilerExtensions/Transformers/AvaloniaXamlIlWellKnownTypes.cs

@ -69,7 +69,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
public IXamlType Thickness { get; }
public IXamlConstructor ThicknessFullConstructor { get; }
public IXamlType ThemeVariant { get; }
public IXamlConstructor ThemeVariantConstructor { get; }
public IXamlType Point { get; }
public IXamlConstructor PointFullConstructor { get; }
public IXamlType Vector { get; }
@ -193,7 +192,6 @@ namespace Avalonia.Markup.Xaml.XamlIl.CompilerExtensions.Transformers
FontFamily = cfg.TypeSystem.GetType("Avalonia.Media.FontFamily");
FontFamilyConstructorUriName = FontFamily.GetConstructor(new List<IXamlType> { Uri, XamlIlTypes.String });
ThemeVariant = cfg.TypeSystem.GetType("Avalonia.Styling.ThemeVariant");
ThemeVariantConstructor = ThemeVariant.GetConstructor(new List<IXamlType> { XamlIlTypes.String });
(IXamlType, IXamlConstructor) GetNumericTypeInfo(string name, IXamlType componentType, int componentCount)
{

13
tests/Avalonia.Markup.Xaml.UnitTests/ThemeDictionariesTests.cs → tests/Avalonia.Markup.Xaml.UnitTests/Xaml/ThemeDictionariesTests.cs

@ -6,10 +6,12 @@ using Avalonia.Styling;
using Moq;
using Xunit;
namespace Avalonia.Markup.Xaml.UnitTests;
namespace Avalonia.Markup.Xaml.UnitTests.Xaml;
public class ThemeDictionariesTests : XamlTestBase
{
public static ThemeVariant Custom { get; } = new(nameof(Custom), ThemeVariant.Light);
[Fact]
public void DynamicResource_Updated_When_Control_Theme_Changed()
{
@ -353,13 +355,14 @@ public class ThemeDictionariesTests : XamlTestBase
Assert.Equal(Colors.Red, ((ISolidColorBrush)border.Background)!.Color);
}
[Fact]
public void Custom_Theme_Can_Be_Defined_In_ThemeDictionaries()
{
var themeVariantScope = (ThemeVariantScope)AvaloniaRuntimeXamlLoader.Load(@"
<ThemeVariantScope xmlns='https://github.com/avaloniaui'
xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
xmlns:local='clr-namespace:Avalonia.Markup.Xaml.UnitTests.Xaml;assembly=Avalonia.Markup.Xaml.UnitTests'
RequestedThemeVariant='Light'>
<ThemeVariantScope.Resources>
<ResourceDictionary>
@ -370,7 +373,7 @@ public class ThemeDictionariesTests : XamlTestBase
<ResourceDictionary x:Key='Light'>
<SolidColorBrush x:Key='DemoBackground'>White</SolidColorBrush>
</ResourceDictionary>
<ResourceDictionary x:Key='Custom'>
<ResourceDictionary x:Key='{x:Static local:ThemeDictionariesTests.Custom}'>
<SolidColorBrush x:Key='DemoBackground'>Pink</SolidColorBrush>
</ResourceDictionary>
</ResourceDictionary.ThemeDictionaries>
@ -380,9 +383,9 @@ public class ThemeDictionariesTests : XamlTestBase
<Border Name='border' Background='{DynamicResource DemoBackground}'/>
</ThemeVariantScope>");
var border = (Border)themeVariantScope.Child!;
themeVariantScope.RequestedThemeVariant = new ThemeVariant("Custom");
themeVariantScope.RequestedThemeVariant = Custom;
Assert.Equal(Colors.Pink, ((ISolidColorBrush)border.Background)!.Color);
}
Loading…
Cancel
Save