Skip to content

Commit

Permalink
Merge pull request #93 from Simnico99/design-time-theming
Browse files Browse the repository at this point in the history
Design time theming
  • Loading branch information
Simnico99 committed Jan 9, 2024
2 parents bea6fff + cd34975 commit 68de4fe
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 75 deletions.
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ Here is an exemple:
</controls:MicaWindow>
```

3. You need to add `<mica:ThemeDictionary Theme="Dark" />` to your App.xaml resources.
3. You need to add `<mica:ThemeDictionary Theme="Auto" />` and `<mica:ControlsDictionary />` to your App.xaml resources.

Here is an exemple:
```xaml
Expand All @@ -158,7 +158,8 @@ Here is an exemple:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<mica:ThemeDictionary Theme="Auto" /> <!-- And Here (You can change to Light or Dark here) -->
<mica:ThemeDictionary DesignModeTheme="Dark" Theme="Auto" /> <!-- And Here (You can change to Light, Dark or auto here) -->
<!-- <mica:ThemeDictionary /> works too-->
<mica:ControlsDictionary /> <!-- This is mandatory -->
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
Expand All @@ -171,7 +172,7 @@ Now get into your Window code:
1. Add the namespace `using MicaWPF.Controls;`.
2. Change the Window inherited class to `MicaWindow`.

Here is an exemple of what it might look like using .NET7:
Here is an exemple of what it might look like using .NET8:
```CSharp
using MicaWPF.Controls;

Expand Down
13 changes: 13 additions & 0 deletions src/MicaWPF.Core/Helpers/DesignTimeHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// <copyright file="DesignTimeHelper.cs" company="Zircon Technology">
// This software is distributed under the MIT license and its code is open-source and free for use, modification, and distribution.
// </copyright>

using System.ComponentModel;
using System.Windows;

namespace MicaWPF.Core.Helpers;

public static class DesignTimeHelper
{
public static bool IsDesignMode { get; } = DesignerProperties.GetIsInDesignMode(new DependencyObject());
}
44 changes: 14 additions & 30 deletions src/MicaWPF.Core/Helpers/ServiceLocatorHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,12 @@ internal static class ServiceLocatorHelper
private static readonly Assembly[] _assemblies = AppDomain.CurrentDomain.GetAssemblies();

/// <summary>
/// Returns the namespace for the current assembly.
/// Returns the namespace for the current MicaWPF assembly if lite is used or not.
/// </summary>
/// <returns>The current namespace.</returns>
public static string GetNamespace()
{
var currentAssembly = _assemblies.FirstOrDefault(x => x.GetName().Name is "MicaWPF");
if (currentAssembly != null)
{
return "MicaWPF";
}

return "MicaWPF.Lite";
return _assemblies.Any(x => x.GetName().Name == "MicaWPF") ? "MicaWPF" : "MicaWPF.Lite";
}

/// <summary>
Expand All @@ -39,26 +33,23 @@ public static T GetService<T>()
{
var serviceType = typeof(T);

var currentAssembly = _assemblies.First(x => x.GetName().Name is "MicaWPF" or "MicaWPF.Lite");

var instance = GetInstanceFromAssembly<T>(currentAssembly, serviceType);
if (instance != null)
{
return instance;
}
// Simplified assembly search with pattern matching
var currentAssembly = _assemblies.FirstOrDefault(x => x.GetName().Name is "MicaWPF" or "MicaWPF.Lite");

// Fallback to MicaWPF.Core
currentAssembly = Assembly.GetAssembly(typeof(ServiceLocatorHelper));
if (currentAssembly != null)
if (currentAssembly is not null)
{
instance = GetInstanceFromAssembly<T>(currentAssembly, serviceType);
if (instance != null)
var instance = GetInstanceFromAssembly<T>(currentAssembly, serviceType);
if (instance is not null)
{
return instance;
}
}

throw new InvalidOperationException($"{typeof(T)} wasn't found in any assembly.");
// Utilizing the 'Assembly.GetAssembly' method directly
var fallbackAssembly = Assembly.GetAssembly(typeof(ServiceLocatorHelper));
var fallbackInstance = fallbackAssembly is not null ? GetInstanceFromAssembly<T>(fallbackAssembly, serviceType) : null;

return fallbackInstance ?? throw new InvalidOperationException($"{serviceType} wasn't found in any assembly.");
}

/// <summary>
Expand All @@ -71,15 +62,8 @@ public static T GetService<T>()
private static T? GetInstanceFromAssembly<T>(Assembly assembly, Type serviceType)
where T : class
{
var typeInAssembly = assembly
.GetTypes()
.FirstOrDefault(t => serviceType.IsAssignableFrom(t) && !t.IsInterface);

if (typeInAssembly != null)
{
return (T?)Activator.CreateInstance(typeInAssembly);
}
var typeInAssembly = assembly.GetTypes().FirstOrDefault(t => serviceType.IsAssignableFrom(t) && !t.IsInterface);

return null;
return typeInAssembly is not null ? Activator.CreateInstance(typeInAssembly) as T : null;
}
}
12 changes: 8 additions & 4 deletions src/MicaWPF.Core/Services/AccentColorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ namespace MicaWPF.Core.Services;
/// </summary>
public class AccentColorService : IAccentColorService
{
private readonly string[] _colorKeys = ["Primary", "Secondary", "Tertiary", "Light3", "Light2", "Light1", string.Empty, "Dark1", "Dark2", "Dark3"];

private bool _isTitleBarAndBorderAccentAware;
private bool _isCheckingTitleBarAndBorderAccent;

Expand All @@ -36,7 +38,10 @@ public AccentColorService()

public bool AccentColorsUpdateFromWindows { get; private set; } = true;

public bool IsTitleBarAndWindowsBorderColored { get; private set; }
public bool IsTitleBarAndWindowsBorderColored
{
get; private set;
}

public bool IsTitleBarAndBorderAccentAware
{
Expand Down Expand Up @@ -73,12 +78,11 @@ public void UpdateAccentsColorsFromWindows()

private void UpdateColorResources(Color primaryAccent, Color secondaryAccent, Color tertiaryAccent)
{
var colorKeys = new string[] { "Primary", "Secondary", "Tertiary", "Light3", "Light2", "Light1", string.Empty, "Dark1", "Dark2", "Dark3" };
var accentColors = new Color[] { primaryAccent, secondaryAccent, tertiaryAccent, AccentColors.SystemAccentColorLight3, AccentColors.SystemAccentColorLight2, AccentColors.SystemAccentColorLight1, AccentColors.SystemAccentColor, AccentColors.SystemAccentColorDark1, AccentColors.SystemAccentColorDark2, AccentColors.SystemAccentColorDark3 };

for (var i = 0; i < colorKeys.Length; i++)
for (var i = 0; i < _colorKeys.Length; i++)
{
Application.Current.Resources[$"MicaWPF{MicaWPFServiceUtility.BrushNamespace}.Colors.SystemAccentColor{colorKeys[i]}"] = accentColors[i];
Application.Current.Resources[$"MicaWPF{MicaWPFServiceUtility.BrushNamespace}.Colors.SystemAccentColor{_colorKeys[i]}"] = accentColors[i];
}

WindowHelper.RefreshAllWindowsContents();
Expand Down
71 changes: 71 additions & 0 deletions src/MicaWPF.Core/Styles/ThemeDictionaryBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
// <copyright file="ThemeDictionaryBase.cs" company="Zircon Technology">
// This software is distributed under the MIT license and its code is open-source and free for use, modification, and distribution.
// </copyright>

using System.Windows;
using System.Windows.Markup;
using MicaWPF.Core.Enums;
using MicaWPF.Core.Helpers;

namespace MicaWPF.Core.Styles;

[Localizability(LocalizationCategory.Ignore)]
[UsableDuringInitialization(true)]
public abstract class ThemeDictionaryBase : ResourceDictionary
{
private WindowsTheme? _theme = null;
private WindowsTheme? _designModeTheme = null;

public ThemeDictionaryBase()
{
if (DesignTimeHelper.IsDesignMode && !_designModeTheme.HasValue)
{
SetTheme(WindowsTheme.Light);
return;
}

if(!_theme.HasValue)
{
SetTheme(WindowsTheme.Auto);
}
}

public virtual string SourceLocation { get; } = string.Empty;

public WindowsTheme Theme
{
get => _theme!.Value;
set
{
_theme = value;
if (!DesignTimeHelper.IsDesignMode)
{
SetTheme(value);
}
}
}

public WindowsTheme DesignModeTheme
{
get => _designModeTheme!.Value;
set
{
_designModeTheme = value;
if (DesignTimeHelper.IsDesignMode)
{
SetTheme(value);
}
}
}

protected void SetTheme(WindowsTheme value)
{
var themeName = value switch
{
WindowsTheme.Dark => "MicaDark",
_ => "MicaLight",
};

Source = new($"{SourceLocation}/{themeName}.xaml", UriKind.Absolute);
}
}
25 changes: 4 additions & 21 deletions src/MicaWPF.Lite/Styles/ThemeDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,11 @@
// This software is distributed under the MIT license and its code is open-source and free for use, modification, and distribution.
// </copyright>

using System.Windows;
using System.Windows.Markup;
using MicaWPF.Core.Enums;
using MicaWPF.Core.Styles;

namespace MicaWPF.Lite.Styles;

[Localizability(LocalizationCategory.Ignore)]
[Ambient]
[UsableDuringInitialization(true)]
public sealed class ThemeDictionary : ResourceDictionary
public sealed class ThemeDictionary : ThemeDictionaryBase
{
public WindowsTheme Theme
{
set
{
var themeName = value switch
{
WindowsTheme.Dark => "MicaDark",
_ => "MicaLight",
};

Source = new($"pack://application:,,,/MicaWPF.Lite;component/Styles/Themes/{themeName}.xaml", UriKind.Absolute);
}
}
}
public override string SourceLocation { get; } = "pack://application:,,,/MicaWPF.Lite;component/Styles/Themes";
}
2 changes: 1 addition & 1 deletion src/MicaWPF/Styles/ControlsDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

namespace MicaWPF.Styles;

[Localizability(LocalizationCategory.Ignore)]
[Ambient]
[Localizability(LocalizationCategory.Ignore)]
[UsableDuringInitialization(true)]
public sealed class ControlsDictionary : ResourceDictionary
{
Expand Down
20 changes: 4 additions & 16 deletions src/MicaWPF/Styles/ThemeDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,14 @@

using System.Windows;
using System.Windows.Markup;
using MicaWPF.Core.Enums;
using MicaWPF.Core.Styles;

namespace MicaWPF.Styles;

[Localizability(LocalizationCategory.Ignore)]
[Ambient]
[Localizability(LocalizationCategory.Ignore)]
[UsableDuringInitialization(true)]
public sealed class ThemeDictionary : ResourceDictionary
public sealed class ThemeDictionary : ThemeDictionaryBase
{
public WindowsTheme Theme
{
set
{
var themeName = value switch
{
WindowsTheme.Dark => "MicaDark",
_ => "MicaLight",
};

Source = new($"pack://application:,,,/MicaWPF;component/Styles/Themes/{themeName}.xaml", UriKind.Absolute);
}
}
public override string SourceLocation { get; } = "pack://application:,,,/MicaWPF;component/Styles/Themes";
}

0 comments on commit 68de4fe

Please sign in to comment.