Merge remote-tracking branch 'origin/dev' into 3.0_major_update
# Conflicts: # Material.Demo/App.axaml # Material.Demo/MainWindow.axaml # Material.Demo/Pages/DialogDemo.axaml # Material.Demo/Pages/DialogDemo.axaml.cs # Material.Demo/Pages/SlidersDemo.axaml # Material.Styles/Converters/AutoCorrectPositionConverter.cs # Material.Styles/DialogHost.axaml # Material.Styles/MaterialToolKit.xaml # Material.Styles/Slider.xaml # Material.Styles/Themes/MaterialThemeBase.cs
This commit is contained in:
@@ -11,6 +11,7 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build solution
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Setup .NET Core
|
||||
|
||||
@@ -6,7 +6,9 @@ on:
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and pack
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.head_commit.message, 'no nightly')"
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .NET
|
||||
@@ -31,6 +33,7 @@ jobs:
|
||||
name: artifacts
|
||||
path: artifacts/
|
||||
numerge:
|
||||
name: Merge packages and publish nightly
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
steps:
|
||||
|
||||
@@ -7,6 +7,7 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
name: Build and pack
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup .NET
|
||||
@@ -32,6 +33,7 @@ jobs:
|
||||
path: artifacts/
|
||||
numerge:
|
||||
runs-on: ubuntu-latest
|
||||
name: Merge packages and publish nightly
|
||||
needs: [build]
|
||||
steps:
|
||||
- name: Checkout Numerge
|
||||
|
||||
+17
-11
@@ -1,15 +1,21 @@
|
||||
<Application xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:themes="clr-namespace:Material.Styles.Themes;assembly=Material.Styles"
|
||||
x:Class="Material.Demo.App" >
|
||||
<Application.Styles>
|
||||
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml" />
|
||||
<themes:MaterialTheme BaseTheme="Light"
|
||||
PrimaryColor="Purple"
|
||||
SecondaryColor="Indigo" />
|
||||
|
||||
<StyleInclude Source="avares://Material.Icons.Avalonia/App.xaml" />
|
||||
<StyleInclude Source="avares://Material.DataGrid/DataGrid.xaml" />
|
||||
<StyleInclude Source="avares://Material.Demo/MaterialXamlDisplay.axaml" />
|
||||
</Application.Styles>
|
||||
xmlns:showMeTheXaml="clr-namespace:ShowMeTheXaml;assembly=ShowMeTheXaml.Avalonia"
|
||||
x:Class="Material.Demo.App">
|
||||
<Application.Styles>
|
||||
<StyleInclude Source="avares://Avalonia.Themes.Default/DefaultTheme.xaml" />
|
||||
<themes:MaterialTheme BaseTheme="Light"
|
||||
PrimaryColor="Purple"
|
||||
SecondaryColor="Indigo" />
|
||||
<StyleInclude Source="avares://Material.Icons.Avalonia/App.xaml" />
|
||||
<StyleInclude Source="avares://Material.DataGrid/DataGrid.xaml" />
|
||||
<StyleInclude Source="avares://ShowMeTheXaml.Avalonia/XamlDisplay.xaml" />
|
||||
<StyleInclude Source="avares://Material.Demo/MaterialXamlDisplay.axaml" />
|
||||
<StyleInclude Source="avares://DialogHost.Avalonia/Styles.xaml" />
|
||||
|
||||
<Style Selector="showMeTheXaml|XamlDisplay">
|
||||
<Setter Property="ClipToBounds" Value="False"></Setter>
|
||||
</Style>
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
@@ -12,6 +12,7 @@
|
||||
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.14" />
|
||||
<PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" />
|
||||
<PackageReference Include="ShowMeTheXaml.Avalonia.Generator" Version="0.3.0" />
|
||||
<PackageReference Include="DialogHost.Avalonia" Version="0.6.0-rc1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Material.Avalonia\Material.Avalonia.csproj" />
|
||||
|
||||
@@ -14,12 +14,12 @@
|
||||
<Style Selector="StackPanel.Content Slider:horizontal" >
|
||||
<Setter Property="Width" Value="300" />
|
||||
</Style>
|
||||
<Style Selector="StackPanel.Content TextBlock" >
|
||||
<Style Selector="StackPanel.Content > TextBlock">
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
<Setter Property="Margin" Value="16,0" />
|
||||
<Setter Property="Text" Value="{Binding $parent.Children[0].Content.Value}" />
|
||||
</Style>
|
||||
<Style Selector="StackPanel.Content" >
|
||||
<Style Selector="StackPanel.Content">
|
||||
<Setter Property="Margin" Value="4 2" />
|
||||
</Style>
|
||||
</StackPanel.Styles>
|
||||
@@ -29,10 +29,10 @@
|
||||
<TextBlock Classes="Headline6 Subheadline2" Text="Slider (Material v1, legacy)" />
|
||||
|
||||
<!-- lol this one are not enabled snap to tick,
|
||||
when dragging thumb could contains a long numerics with decimal point. -->
|
||||
<StackPanel Classes="Content" Orientation="Horizontal" >
|
||||
<showMeTheXaml:XamlDisplay UniqueId="RegularSlider0" >
|
||||
<Slider Classes="material-v1" />
|
||||
when dragging thumb could contains a long numerics with decimal point. -->
|
||||
<StackPanel Classes="Content" Orientation="Horizontal">
|
||||
<showMeTheXaml:XamlDisplay UniqueId="RegularSlider0">
|
||||
<Slider Classes="material-v1" ToolTip.Tip="Just show me my tooltip!" />
|
||||
</showMeTheXaml:XamlDisplay>
|
||||
<TextBlock MinWidth="120" />
|
||||
</StackPanel>
|
||||
|
||||
@@ -11,9 +11,9 @@ namespace Material.Styles.Converters
|
||||
public class AutoCorrectPositionConverter : IMultiValueConverter
|
||||
{
|
||||
public static readonly Transform Empty = new MatrixTransform();
|
||||
|
||||
|
||||
public static double DefaultOffsetY = 0;
|
||||
|
||||
|
||||
private static double GetOffLeft(double offsetX) => offsetX;
|
||||
|
||||
private static double GetOffRight(Rect bounds, double clipW, double offsetX)
|
||||
@@ -25,7 +25,8 @@ namespace Material.Styles.Converters
|
||||
|
||||
private static Vector GetTranslate(Matrix m)
|
||||
{
|
||||
return Matrix.TryDecomposeTransform(m, out var decomposed) ? decomposed.Translate : Vector.Zero;
|
||||
return Matrix.TryDecomposeTransform(m, out var decomposed) ?
|
||||
decomposed.Translate : Vector.Zero;
|
||||
}
|
||||
|
||||
public object Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
|
||||
@@ -34,17 +35,17 @@ namespace Material.Styles.Converters
|
||||
|
||||
if (values.Count <= 1 || values.Count > 2)
|
||||
return Empty;
|
||||
|
||||
|
||||
if (values[1] is not Rect clip)
|
||||
return Empty;
|
||||
|
||||
if (values[0] is not TransformedBounds postTransformations)
|
||||
return Empty;
|
||||
|
||||
|
||||
var t = postTransformations.Transform;
|
||||
var b = postTransformations.Bounds;
|
||||
var c = clip;
|
||||
|
||||
|
||||
var translate = GetTranslate(t);
|
||||
|
||||
var left = GetOffLeft(translate.X);
|
||||
@@ -57,10 +58,10 @@ namespace Material.Styles.Converters
|
||||
}
|
||||
else if (right > 0)
|
||||
{
|
||||
offsetX = -right;
|
||||
offsetX = -right;
|
||||
// _prevCorrect = new Vector(offsetX, DefaultOffsetY);
|
||||
}
|
||||
|
||||
|
||||
return new TranslateTransform(offsetX, DefaultOffsetY);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<Styles xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:dialogHost="clr-namespace:DialogHost;assembly=DialogHost.Avalonia"
|
||||
xmlns:assists="clr-namespace:Material.Styles.Assists"
|
||||
xmlns:controls="clr-namespace:Material.Styles.Controls">
|
||||
<Style Selector="dialogHost|DialogHost">
|
||||
<Setter Property="PopupTemplate">
|
||||
<ControlTemplate>
|
||||
<controls:Card assists:ShadowAssist.ShadowDepth="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=(assists:ShadowAssist.ShadowDepth)}"
|
||||
CornerRadius="{Binding Path=(dialogHost:DialogHostStyle.CornerRadius), RelativeSource={RelativeSource FindAncestor, AncestorType=dialogHost:DialogHost}}"
|
||||
Padding="{TemplateBinding Padding}"
|
||||
Content="{TemplateBinding Content}"
|
||||
ContentTemplate="{TemplateBinding ContentTemplate}" />
|
||||
</ControlTemplate>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Styles>
|
||||
@@ -56,7 +56,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Avalonia" Version="0.10.11" />
|
||||
<PackageReference Include="DialogHost.Avalonia" Version="0.4.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -23,11 +23,6 @@
|
||||
<StyleInclude Source="avares://Material.Styles/CircleClockPickerCell.axaml"/>
|
||||
<StyleInclude Source="avares://Material.Styles/CircleClockPicker.axaml"/>
|
||||
|
||||
<!-- dialog host -->
|
||||
|
||||
<StyleInclude Source="avares://DialogHost.Avalonia/Styles.xaml" />
|
||||
<StyleInclude Source="avares://Material.Styles/DialogHost.axaml" />
|
||||
|
||||
<!-- Basic controls -->
|
||||
|
||||
<!-- Buttons -->
|
||||
@@ -100,4 +95,7 @@
|
||||
<!-- Custom controls (High-priority) -->
|
||||
<StyleInclude Source="avares://Material.Styles/SideSheet.xaml"/>
|
||||
|
||||
<!-- DialogHost.Avalonia -->
|
||||
<!-- dialog host style have been removed for avoid unnecessary package linking -->
|
||||
<!-- you can still add it manually https://github.com/AvaloniaUtils/DialogHost.Avalonia -->
|
||||
</Styles>
|
||||
@@ -49,11 +49,18 @@ namespace Material.Styles.Themes
|
||||
_themeUpdaterDisposable = baseThemeObservable
|
||||
.Merge(primaryColorObservable)
|
||||
.Merge(secondaryColorObservable)
|
||||
.Where(_ => _isLoaded)
|
||||
.Throttle(TimeSpan.FromMilliseconds(100))
|
||||
.ObserveOn(new AvaloniaSynchronizationContext())
|
||||
.Subscribe(_ => CurrentTheme = _theme);
|
||||
}
|
||||
|
||||
private bool _isLoaded;
|
||||
protected override ITheme? ProvideInitialTheme() {
|
||||
_isLoaded = true;
|
||||
return _theme;
|
||||
}
|
||||
|
||||
public static readonly StyledProperty<BaseThemeMode> BaseThemeProperty
|
||||
= AvaloniaProperty.Register<MaterialTheme, BaseThemeMode>(nameof(BaseTheme));
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reactive.Linq;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Avalonia;
|
||||
@@ -43,7 +44,7 @@ namespace Material.Styles.Themes
|
||||
{
|
||||
}
|
||||
|
||||
private IResourceDictionary LoadedResourceDictionary => (Loaded as Avalonia.Styling.Styles)!.Resources;
|
||||
private IResourceDictionary LoadedResourceDictionary => (_loaded as Avalonia.Styling.Styles)!.Resources;
|
||||
|
||||
public static readonly DirectProperty<MaterialThemeBase, ITheme> CurrentThemeProperty =
|
||||
AvaloniaProperty.RegisterDirect<MaterialThemeBase, ITheme>(
|
||||
@@ -59,13 +60,10 @@ namespace Material.Styles.Themes
|
||||
/// <returns>
|
||||
/// Returns a STRUCT implementing ITheme interface
|
||||
/// </returns>
|
||||
public ITheme CurrentTheme
|
||||
{
|
||||
public ITheme CurrentTheme {
|
||||
get => new ThemeStruct(_currentTheme);
|
||||
set
|
||||
{
|
||||
set {
|
||||
var oldTheme = _currentTheme;
|
||||
|
||||
var newTheme = new ThemeStruct(value);
|
||||
|
||||
if (EqualityComparer<ITheme>.Default.Equals(oldTheme, newTheme))
|
||||
@@ -73,7 +71,7 @@ namespace Material.Styles.Themes
|
||||
|
||||
_currentTheme = newTheme;
|
||||
RaisePropertyChanged(CurrentThemeProperty, oldTheme, newTheme);
|
||||
StartUpdatingTheme(oldTheme, newTheme);
|
||||
if (!_isLoading) StartUpdatingTheme(oldTheme, newTheme);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,28 +110,34 @@ namespace Material.Styles.Themes
|
||||
|
||||
_loaded = new Avalonia.Styling.Styles {_controlsStyles};
|
||||
|
||||
var initialTheme = ProvideInitialTheme();
|
||||
if (initialTheme != null) {
|
||||
UpdateSolidColorBrush(null, initialTheme, LoadedResourceDictionary, InvokeAndReturnTask).Wait();
|
||||
CurrentTheme = initialTheme;
|
||||
}
|
||||
|
||||
_isLoading = false;
|
||||
|
||||
return _loaded!;
|
||||
|
||||
Task InvokeAndReturnTask(Action action, DispatcherPriority _) {
|
||||
action();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool IResourceNode.HasResources => (Loaded as IResourceProvider)?.HasResources ?? false;
|
||||
IReadOnlyList<IStyle> IStyle.Children => _loaded?.Children ?? Array.Empty<IStyle>();
|
||||
|
||||
public event EventHandler OwnerChanged
|
||||
{
|
||||
add
|
||||
{
|
||||
if (Loaded is IResourceProvider rp)
|
||||
{
|
||||
public event EventHandler OwnerChanged {
|
||||
add {
|
||||
if (Loaded is IResourceProvider rp) {
|
||||
rp.OwnerChanged += value;
|
||||
}
|
||||
}
|
||||
remove
|
||||
{
|
||||
if (Loaded is IResourceProvider rp)
|
||||
{
|
||||
remove {
|
||||
if (Loaded is IResourceProvider rp) {
|
||||
rp.OwnerChanged -= value;
|
||||
}
|
||||
}
|
||||
@@ -155,6 +159,20 @@ namespace Material.Styles.Themes
|
||||
void IResourceProvider.AddOwner(IResourceHost owner) => (Loaded as IResourceProvider)?.AddOwner(owner);
|
||||
void IResourceProvider.RemoveOwner(IResourceHost owner) => (Loaded as IResourceProvider)?.RemoveOwner(owner);
|
||||
|
||||
/// <summary>
|
||||
/// This method will be called to get the theme that will be applied at the start of the application.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// All elements specified in the App.xaml are already initialized, all properties specified in the markup are assigned.
|
||||
/// At this point, avalonia begins to collect and initialize styles and resources.
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// The theme that will be applied initially. <c>null</c> if the theme does not need to be applied initially.
|
||||
/// </returns>
|
||||
protected virtual ITheme? ProvideInitialTheme() {
|
||||
return null;
|
||||
}
|
||||
|
||||
private CancellationTokenSource? _currentCancellationTokenSource;
|
||||
private Task? _currentThemeUpdateTask;
|
||||
|
||||
@@ -169,115 +187,89 @@ namespace Material.Styles.Themes
|
||||
if (_currentThemeUpdateTask != null) await _currentThemeUpdateTask;
|
||||
if (!currentToken.IsCancellationRequested)
|
||||
{
|
||||
_currentThemeUpdateTask = UpdateThemeAsync(oldTheme, newTheme);
|
||||
var task = UpdateSolidColorBrush(oldTheme, newTheme, LoadedResourceDictionary,
|
||||
Dispatcher.UIThread.InvokeAsync);
|
||||
task.ContinueWith(delegate
|
||||
{
|
||||
ThemeChanged?.Invoke(this, EventArgs.Empty);
|
||||
}, CancellationToken.None);
|
||||
|
||||
_currentThemeUpdateTask = task;
|
||||
}
|
||||
});
|
||||
|
||||
private Task UpdateThemeAsync(ITheme? oldTheme, ITheme newTheme)
|
||||
{
|
||||
var task = Task.WhenAll(
|
||||
// Primary
|
||||
UpdateSolidColorBrush("PrimaryHueLightForegroundBrush", oldTheme?.PrimaryLight.ForegroundColor,
|
||||
newTheme.PrimaryLight.ForegroundColor),
|
||||
UpdateSolidColorBrush("PrimaryHueMidForegroundBrush", oldTheme?.PrimaryMid.ForegroundColor,
|
||||
newTheme.PrimaryMid.ForegroundColor),
|
||||
UpdateSolidColorBrush("PrimaryHueDarkForegroundBrush", oldTheme?.PrimaryDark.ForegroundColor,
|
||||
newTheme.PrimaryDark.ForegroundColor),
|
||||
UpdateSolidColorBrush("PrimaryHueLightBrush", oldTheme?.PrimaryLight.Color,
|
||||
newTheme.PrimaryLight.Color),
|
||||
UpdateSolidColorBrush("PrimaryHueMidBrush", oldTheme?.PrimaryMid.Color, newTheme.PrimaryMid.Color),
|
||||
UpdateSolidColorBrush("PrimaryHueDarkBrush", oldTheme?.PrimaryDark.Color, newTheme.PrimaryDark.Color),
|
||||
// Secondary
|
||||
UpdateSolidColorBrush("SecondaryHueLightForegroundBrush?", oldTheme?.SecondaryLight.ForegroundColor,
|
||||
newTheme.SecondaryLight.ForegroundColor),
|
||||
UpdateSolidColorBrush("SecondaryHueMidForegroundBrush", oldTheme?.SecondaryMid.ForegroundColor,
|
||||
newTheme.SecondaryMid.ForegroundColor),
|
||||
UpdateSolidColorBrush("SecondaryHueDarkForegroundBrush", oldTheme?.SecondaryDark.ForegroundColor,
|
||||
newTheme.SecondaryDark.ForegroundColor),
|
||||
UpdateSolidColorBrush("SecondaryHueLightBrush", oldTheme?.SecondaryLight.Color,
|
||||
newTheme.SecondaryLight.Color),
|
||||
UpdateSolidColorBrush("SecondaryHueMidBrush", oldTheme?.SecondaryMid.Color,
|
||||
newTheme.SecondaryMid.Color),
|
||||
UpdateSolidColorBrush("SecondaryHueDarkBrush", oldTheme?.SecondaryDark.Color,
|
||||
newTheme.SecondaryDark.Color),
|
||||
// Other
|
||||
UpdateSolidColorBrush("ValidationErrorBrush", oldTheme?.ValidationError, newTheme.ValidationError),
|
||||
UpdateSolidColorBrush("MaterialDesignBackground", oldTheme?.Background, newTheme.Background),
|
||||
UpdateSolidColorBrush("MaterialDesignPaper", oldTheme?.Paper, newTheme.Paper),
|
||||
UpdateSolidColorBrush("MaterialDesignCardBackground", oldTheme?.CardBackground,
|
||||
newTheme.CardBackground),
|
||||
UpdateSolidColorBrush("MaterialDesignToolBarBackground", oldTheme?.ToolBarBackground,
|
||||
newTheme.ToolBarBackground),
|
||||
UpdateSolidColorBrush("MaterialDesignBody", oldTheme?.Body, newTheme.Body),
|
||||
UpdateSolidColorBrush("MaterialDesignBodyLight", oldTheme?.BodyLight, newTheme.BodyLight),
|
||||
UpdateSolidColorBrush("MaterialDesignColumnHeader", oldTheme?.ColumnHeader, newTheme.ColumnHeader),
|
||||
UpdateSolidColorBrush("MaterialDesignCheckBoxOff", oldTheme?.CheckBoxOff, newTheme.CheckBoxOff),
|
||||
UpdateSolidColorBrush("MaterialDesignCheckBoxDisabled", oldTheme?.CheckBoxDisabled,
|
||||
newTheme.CheckBoxDisabled),
|
||||
UpdateSolidColorBrush("MaterialDesignTextBoxBorder", oldTheme?.TextBoxBorder, newTheme.TextBoxBorder),
|
||||
UpdateSolidColorBrush("MaterialDesignDivider", oldTheme?.Divider, newTheme.Divider),
|
||||
UpdateSolidColorBrush("MaterialDesignSelection", oldTheme?.Selection, newTheme.Selection),
|
||||
UpdateSolidColorBrush("MaterialDesignToolForeground", oldTheme?.ToolForeground,
|
||||
newTheme.ToolForeground),
|
||||
UpdateSolidColorBrush("MaterialDesignToolBackground", oldTheme?.ToolBackground,
|
||||
newTheme.ToolBackground),
|
||||
UpdateSolidColorBrush("MaterialDesignFlatButtonClick", oldTheme?.FlatButtonClick,
|
||||
newTheme.FlatButtonClick),
|
||||
UpdateSolidColorBrush("MaterialDesignFlatButtonRipple", oldTheme?.FlatButtonRipple,
|
||||
newTheme.FlatButtonRipple),
|
||||
UpdateSolidColorBrush("MaterialDesignToolTipBackground", oldTheme?.ToolTipBackground,
|
||||
newTheme.ToolTipBackground),
|
||||
UpdateSolidColorBrush("MaterialDesignChipBackground", oldTheme?.ChipBackground,
|
||||
newTheme.ChipBackground),
|
||||
UpdateSolidColorBrush("MaterialDesignSnackbarBackground", oldTheme?.SnackbarBackground,
|
||||
newTheme.SnackbarBackground),
|
||||
UpdateSolidColorBrush("MaterialDesignSnackbarMouseOver", oldTheme?.SnackbarMouseOver,
|
||||
newTheme.SnackbarMouseOver),
|
||||
UpdateSolidColorBrush("MaterialDesignSnackbarRipple", oldTheme?.SnackbarRipple,
|
||||
newTheme.SnackbarRipple),
|
||||
UpdateSolidColorBrush("MaterialDesignTextFieldBoxBackground", oldTheme?.TextFieldBoxBackground,
|
||||
newTheme.TextFieldBoxBackground),
|
||||
UpdateSolidColorBrush("MaterialDesignTextFieldBoxHoverBackground",
|
||||
oldTheme?.TextFieldBoxHoverBackground, newTheme.TextFieldBoxHoverBackground),
|
||||
UpdateSolidColorBrush("MaterialDesignTextFieldBoxDisabledBackground",
|
||||
oldTheme?.TextFieldBoxDisabledBackground, newTheme.TextFieldBoxDisabledBackground),
|
||||
UpdateSolidColorBrush("MaterialDesignTextAreaBorder", oldTheme?.TextAreaBorder,
|
||||
newTheme.TextAreaBorder),
|
||||
UpdateSolidColorBrush("MaterialDesignTextAreaInactiveBorder", oldTheme?.TextAreaInactiveBorder,
|
||||
newTheme.TextAreaInactiveBorder),
|
||||
UpdateSolidColorBrush("MaterialDesignDataGridRowHoverBackground", oldTheme?.DataGridRowHoverBackground,
|
||||
newTheme.DataGridRowHoverBackground)
|
||||
);
|
||||
task.ContinueWith(delegate { ThemeChanged?.Invoke(this, EventArgs.Empty); });
|
||||
return task;
|
||||
}
|
||||
private static IReadOnlyDictionary<string, Func<ITheme, Color>> UpdatableColors =>
|
||||
new Dictionary<string, Func<ITheme, Color>> {
|
||||
{ "PrimaryHueLightForegroundBrush", theme => theme.PrimaryLight.ForegroundColor },
|
||||
{ "PrimaryHueMidForegroundBrush", theme => theme.PrimaryMid.ForegroundColor },
|
||||
{ "PrimaryHueDarkForegroundBrush", theme => theme.PrimaryDark.ForegroundColor },
|
||||
{ "PrimaryHueLightBrush", theme => theme.PrimaryLight.Color },
|
||||
{ "PrimaryHueMidBrush", theme => theme.PrimaryMid.Color },
|
||||
{ "PrimaryHueDarkBrush", theme => theme.PrimaryDark.Color },
|
||||
{ "SecondaryHueLightForegroundBrush", theme => theme.SecondaryLight.ForegroundColor },
|
||||
{ "SecondaryHueMidForegroundBrush", theme => theme.SecondaryMid.ForegroundColor },
|
||||
{ "SecondaryHueDarkForegroundBrush", theme => theme.SecondaryDark.ForegroundColor },
|
||||
{ "SecondaryHueLightBrush", theme => theme.SecondaryLight.Color },
|
||||
{ "SecondaryHueMidBrush", theme => theme.SecondaryMid.Color },
|
||||
{ "SecondaryHueDarkBrush", theme => theme.SecondaryDark.Color },
|
||||
{ "ValidationErrorBrush", theme => theme.ValidationError },
|
||||
{ "MaterialDesignBackground", theme => theme.Background },
|
||||
{ "MaterialDesignPaper", theme => theme.Paper },
|
||||
{ "MaterialDesignCardBackground", theme => theme.CardBackground },
|
||||
{ "MaterialDesignToolBarBackground", theme => theme.ToolBarBackground },
|
||||
{ "MaterialDesignBody", theme => theme.Body },
|
||||
{ "MaterialDesignBodyLight", theme => theme.BodyLight },
|
||||
{ "MaterialDesignColumnHeader", theme => theme.ColumnHeader },
|
||||
{ "MaterialDesignCheckBoxOff", theme => theme.CheckBoxOff },
|
||||
{ "MaterialDesignCheckBoxDisabled", theme => theme.CheckBoxDisabled },
|
||||
{ "MaterialDesignTextBoxBorder", theme => theme.TextBoxBorder },
|
||||
{ "MaterialDesignDivider", theme => theme.Divider },
|
||||
{ "MaterialDesignSelection", theme => theme.Selection },
|
||||
{ "MaterialDesignToolForeground", theme => theme.ToolForeground },
|
||||
{ "MaterialDesignToolBackground", theme => theme.ToolBackground },
|
||||
{ "MaterialDesignFlatButtonClick", theme => theme.FlatButtonClick },
|
||||
{ "MaterialDesignFlatButtonRipple", theme => theme.FlatButtonRipple },
|
||||
{ "MaterialDesignToolTipBackground", theme => theme.ToolTipBackground },
|
||||
{ "MaterialDesignChipBackground", theme => theme.ChipBackground },
|
||||
{ "MaterialDesignSnackbarBackground", theme => theme.SnackbarBackground },
|
||||
{ "MaterialDesignSnackbarMouseOver", theme => theme.SnackbarMouseOver },
|
||||
{ "MaterialDesignSnackbarRipple", theme => theme.SnackbarRipple },
|
||||
{ "MaterialDesignTextFieldBoxBackground", theme => theme.TextFieldBoxBackground },
|
||||
{ "MaterialDesignTextFieldBoxHoverBackground", theme => theme.TextFieldBoxHoverBackground },
|
||||
{ "MaterialDesignTextFieldBoxDisabledBackground", theme => theme.TextFieldBoxDisabledBackground },
|
||||
{ "MaterialDesignTextAreaBorder", theme => theme.TextAreaBorder },
|
||||
{ "MaterialDesignTextAreaInactiveBorder", theme => theme.TextAreaInactiveBorder },
|
||||
{ "MaterialDesignDataGridRowHoverBackground", theme => theme.DataGridRowHoverBackground },
|
||||
};
|
||||
|
||||
private Task UpdateSolidColorBrush(string brushName, Color? oldColor, Color newColor)
|
||||
{
|
||||
if (oldColor == newColor) return Task.CompletedTask;
|
||||
return LoadedResourceDictionary.TryGetValue(brushName, out var b) && b is SolidColorBrush brush
|
||||
? UpdateBrushAsync()
|
||||
: CreateBrushAsync();
|
||||
private static Task UpdateSolidColorBrush(ITheme? oldTheme, ITheme newTheme, IResourceDictionary resourceDictionary, Func<Action, DispatcherPriority, Task> contextSync) {
|
||||
return Task.WhenAll(UpdatableColors.Select(UpdateColorAsync).ToArray());
|
||||
|
||||
Task UpdateBrushAsync()
|
||||
=> Dispatcher.UIThread.InvokeAsync(() => { brush.Color = newColor; });
|
||||
Task UpdateColorAsync(KeyValuePair<string, Func<ITheme, Color>> pair) {
|
||||
var oldColor = oldTheme != null ? pair.Value(oldTheme) : (Color?)null;
|
||||
var newColor = pair.Value(newTheme);
|
||||
|
||||
Task CreateBrushAsync()
|
||||
=> Dispatcher.UIThread.InvokeAsync(() =>
|
||||
{
|
||||
LoadedResourceDictionary[brushName] = new SolidColorBrush(newColor)
|
||||
{
|
||||
Transitions = new Transitions
|
||||
{
|
||||
new ColorTransition
|
||||
{
|
||||
Duration = TimeSpan.FromSeconds(0.35),
|
||||
Easing = new SineEaseOut(),
|
||||
Property = SolidColorBrush.ColorProperty
|
||||
if (oldColor == newColor) return Task.CompletedTask;
|
||||
return oldColor != null && resourceDictionary.TryGetValue(pair.Key, out var b) && b is SolidColorBrush brush
|
||||
? UpdateBrushAsync()
|
||||
: CreateBrushAsync();
|
||||
|
||||
Task UpdateBrushAsync()
|
||||
=> contextSync(() => {
|
||||
brush.Color = newColor;
|
||||
}, DispatcherPriority.Normal);
|
||||
|
||||
Task CreateBrushAsync()
|
||||
=> contextSync(() => {
|
||||
resourceDictionary[pair.Key] = new SolidColorBrush(newColor) {
|
||||
Transitions = new Transitions {
|
||||
new ColorTransition {
|
||||
Duration = TimeSpan.FromSeconds(0.35), Easing = new SineEaseOut(), Property = SolidColorBrush.ColorProperty
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
};
|
||||
}, DispatcherPriority.Normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,9 +38,12 @@ Check out the [getting started](https://github.com/AvaloniaCommunity/Material.Av
|
||||
</Application.Styles>
|
||||
</Application>
|
||||
```
|
||||
|
||||
# <img src="/FavIcon.svg" width="32" height="32"> Useful links
|
||||
- [Advanced theming](https://github.com/AvaloniaCommunity/Material.Avalonia/wiki/Advanced-Theming) wiki page
|
||||
- [Nightly packages](https://github.com/AvaloniaCommunity/Material.Avalonia/wiki/Using-nightly-build-feed) wiki page
|
||||
- [Material Design Icons](https://github.com/AvaloniaUtils/Material.Icons.Avalonia) icon pack support
|
||||
- [DialogHost.Avalonia](https://github.com/AvaloniaUtils/DialogHost.Avalonia) that provides a simple way to display a dialog
|
||||
|
||||
### Powered by
|
||||
|
||||
|
||||
Reference in New Issue
Block a user