Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions DarkNet/WPF/ElementSkinManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace Dark.Net.Wpf;

public class ElementSkinManager {

private ResourceDictionary? _skinResources;
private Uri? _lightThemeResources;
private Uri? _darkThemeResources;
private readonly IDarkNet _darkNet;
private readonly FrameworkElement element;

/// <summary>
/// Create a new instance that uses the default <see cref="DarkNet"/> instance.
/// </summary>
public ElementSkinManager(FrameworkElement element): this(DarkNet.Instance, element) { }

/// <summary>
/// Create a new instance that uses a custom <see cref="IDarkNet"/> instance.
/// </summary>
public ElementSkinManager(IDarkNet darkNet, FrameworkElement element) {
_darkNet = darkNet;
this.element = element;
}

public virtual void RegisterSkins(Uri lightThemeResources, Uri darkThemeResources) {
_darkThemeResources = darkThemeResources;
_lightThemeResources = lightThemeResources;

if (_skinResources == null) {
Collection<ResourceDictionary> windowResources = element.Resources.MergedDictionaries;
_skinResources = windowResources.FirstOrDefault(r => r.Source.Equals(lightThemeResources) || r.Source.Equals(darkThemeResources));

if (_skinResources == null) {
_skinResources = new ResourceDictionary();
windowResources.Add(_skinResources);
}

UpdateTheme(_darkNet.EffectiveCurrentProcessThemeIsDark);
}
}

/// <summary>
/// <para>Change the <see cref="FrameworkElement"/>'s <see cref="ResourceDictionary"/>'s <see cref="ResourceDictionary.Source"/> between the light and dark URIs which were set by
/// <see cref="RegisterSkins"/>.</para>
/// <para>This is called once by <see cref="RegisterSkins"/>, and again anytime you want to switch between themes for the control.</para>
/// </summary>
/// <param name="isDarkTheme"><see langword="true" /> to set dark theme, or <see langword="false"/> to set light theme.</param>
public virtual void UpdateTheme(bool isDarkTheme) {
if (_skinResources != null) {
_skinResources.Source = isDarkTheme ? _darkThemeResources : _lightThemeResources;
}
}

/// <summary>
/// <para>Change the <see cref="FrameworkElement"/>'s <see cref="ResourceDictionary"/>'s <see cref="ResourceDictionary.Source"/> between the light and dark URIs which were set by
/// <see cref="RegisterSkins"/>.</para>
/// <para>This is called once by <see cref="RegisterSkins"/>, and again anytime you want to switch between themes for the control.</para>
/// </summary>
/// <param name="theme"><see cref="Theme.Dark"/> to set dark theme, <see cref="Theme.Light"/> to set light theme, or <see cref="Theme.Auto"/> to set current process theme</param>
public virtual void UpdateTheme(Theme theme)
{
var isDarkTheme = theme switch
{
Theme.Auto => _darkNet.EffectiveCurrentProcessThemeIsDark,
Theme.Light => false,
Theme.Dark => true,
_ => throw new ArgumentOutOfRangeException(nameof(theme), theme, null)
};
UpdateTheme(isDarkTheme);
}

}
41 changes: 41 additions & 0 deletions darknet-demo-wpf-2/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
[*]

# Exception Analyzers: Exception adjustments syntax error
# default = error
; dotnet_diagnostic.Ex0001.severity = none

# Exception Analyzers: Exception adjustments syntax error: Symbol does not exist or identifier is invalid
# default = warning
; dotnet_diagnostic.Ex0002.severity = none

# Exception Analyzers: Member may throw undocumented exception
# default = warning
dotnet_diagnostic.Ex0100.severity = none

# Exception Analyzers: Member accessor may throw undocumented exception
# default = warning
dotnet_diagnostic.Ex0101.severity = none

# Exception Analyzers: Implicit constructor may throw undocumented exception
# default = warning
dotnet_diagnostic.Ex0103.severity = none

# Exception Analyzers: Member initializer may throw undocumented exception
# default = warning
dotnet_diagnostic.Ex0104.severity = none

# Exception Analyzers: Delegate created from member may throw undocumented exception
# default = silent
; dotnet_diagnostic.Ex0120.severity = none

# Exception Analyzers: Delegate created from anonymous function may throw undocumented exception
# default = silent
; dotnet_diagnostic.Ex0121.severity = none

# Exception Analyzers: Member is documented as throwing exception not documented on member in base or interface type
# default = warning
dotnet_diagnostic.Ex0200.severity = none

# Exception Analyzers: Member accessor is documented as throwing exception not documented on member in base or interface type
# default = warning
dotnet_diagnostic.Ex0201.severity = none
4 changes: 4 additions & 0 deletions darknet-demo-wpf-2/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<Application x:Class="darknet_demo_wpf_2.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
</Application>
30 changes: 30 additions & 0 deletions darknet-demo-wpf-2/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Windows;
using Dark.Net;
using Dark.Net.Wpf;

namespace darknet_demo_wpf_2;

public partial class App {

protected override void OnStartup(StartupEventArgs e) {
const Theme processTheme = Theme.Auto;
IDarkNet darkNet = DarkNet.Instance;
darkNet.SetCurrentProcessTheme(processTheme);
Console.WriteLine($"Process theme is {processTheme}");
Console.WriteLine($"System theme is {(darkNet.UserDefaultAppThemeIsDark ? "Dark" : "Light")}");
Console.WriteLine($"Taskbar theme {(darkNet.UserTaskbarThemeIsDark ? "Dark" : "Light")}");

darkNet.UserDefaultAppThemeIsDarkChanged += (_, isSystemDarkTheme) => { Console.WriteLine($"System theme is {(isSystemDarkTheme ? "Dark" : "Light")}"); };
darkNet.UserTaskbarThemeIsDarkChanged += (_, isTaskbarDarkTheme) => { Console.WriteLine($"Taskbar theme is {(isTaskbarDarkTheme ? "Dark" : "Light")}"); };

base.OnStartup(e);

var w1 = new MainWindow();
var w2 = new MainWindow();
w1.Show();
w2.Show();

}

}
10 changes: 10 additions & 0 deletions darknet-demo-wpf-2/AssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System.Windows;

[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]
32 changes: 32 additions & 0 deletions darknet-demo-wpf-2/MainWindow.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<Window x:Class="darknet_demo_wpf_2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="WPF demo - .NET 6 - DarkNet" Height="450" Width="800" Icon="/icon.png" Style="{DynamicResource windowStyle}">
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!--
This will be replaced with the correct skin to match the title bar theme by SkinManager
Also, "light" is more DesignTime-friendly
-->
<ResourceDictionary Source="Skins/Skin.Light.xaml" />
</ResourceDictionary.MergedDictionaries>
<!--Place all your window resources here (inside ResourceDictionary)-->
</ResourceDictionary>
</Window.Resources>
<Grid>
<StackPanel Orientation="Vertical">
<Label Content="Try changing your color mode in Windows Settings to see this app's title bar, menu, and client area react." />
<Label Content="Also try clicking checkbox in both windows to see how they change theme independently." />
<CheckBox x:Name="darkModeCheckbox" Content="Dark mode" Click="onDarkModeCheckboxChanged" IsThreeState="True" IsChecked="{x:Null}" />
<StackPanel Name="SpecialPanel" Margin="20" Orientation="Horizontal" HorizontalAlignment="Center">
<Label Margin="10" Content="This panel's theme is set separately"></Label>
<CheckBox Margin="10" x:Name="darkModePanelCheckbox" Content="Dark mode this panel" Click="onDarkModePanelCheckboxChanged" IsThreeState="True" IsChecked="{x:Null}" />
</StackPanel>
</StackPanel>

</Grid>
</Window>
46 changes: 46 additions & 0 deletions darknet-demo-wpf-2/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using System.Windows;
using Dark.Net;
using Dark.Net.Wpf;

namespace darknet_demo_wpf_2;

public partial class MainWindow {
private readonly Theme windowTheme;
private readonly ElementSkinManager skinManager;
private readonly ElementSkinManager panelSkinManager;

public MainWindow() {
InitializeComponent();

windowTheme = Theme.Auto;
skinManager = new ElementSkinManager(this);
panelSkinManager = new ElementSkinManager(this.SpecialPanel);
DarkNet.Instance.SetWindowThemeWpf(this, windowTheme);
skinManager.RegisterSkins(new Uri("Skins/Skin.Light.xaml", UriKind.Relative), new Uri("Skins/Skin.Dark.xaml", UriKind.Relative));
skinManager.UpdateTheme(windowTheme);
panelSkinManager.RegisterSkins(new Uri("Skins/Panel.Light.xaml", UriKind.Relative), new Uri("Skins/Panel.Dark.xaml", UriKind.Relative));
panelSkinManager.UpdateTheme(windowTheme);
Console.WriteLine($"Window theme is {windowTheme}");
}

private void onDarkModeCheckboxChanged(object sender, RoutedEventArgs e) {
Theme theme = darkModeCheckbox.IsChecked switch {
true => Theme.Dark,
false => Theme.Light,
null => Theme.Auto
};
DarkNet.Instance.SetWindowThemeWpf(this, theme);
skinManager.UpdateTheme(theme);
}

private void onDarkModePanelCheckboxChanged(object sender, RoutedEventArgs e) {
Theme theme = darkModePanelCheckbox.IsChecked switch {
true => Theme.Dark,
false => Theme.Light,
null => Theme.Auto
};
panelSkinManager.UpdateTheme(theme);
}

}
17 changes: 17 additions & 0 deletions darknet-demo-wpf-2/Properties/PublishProfiles/FolderProfile.pubxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
https://go.microsoft.com/fwlink/?LinkID=208121.
-->
<Project>
<PropertyGroup>
<Configuration>Release</Configuration>
<Platform>Any CPU</Platform>
<PublishDir>bin\Release\net6.0-windows\win-x64\publish\</PublishDir>
<PublishProtocol>FileSystem</PublishProtocol>
<TargetFramework>net6.0-windows</TargetFramework>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<SelfContained>false</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>false</PublishReadyToRun>
</PropertyGroup>
</Project>
12 changes: 12 additions & 0 deletions darknet-demo-wpf-2/Skins/Panel.Dark.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!-- ReSharper disable InconsistentNaming -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Style TargetType="StackPanel">
<Setter Property="Background" Value="MidnightBlue"></Setter>
</Style>
<Style TargetType="Label">
<Setter Property="Foreground" Value="White"></Setter>
</Style>

</ResourceDictionary>
12 changes: 12 additions & 0 deletions darknet-demo-wpf-2/Skins/Panel.Light.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!-- ReSharper disable InconsistentNaming -->
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Style TargetType="StackPanel">
<Setter Property="Background" Value="LightSkyBlue"></Setter>
</Style>
<Style TargetType="Label">
<Setter Property="Foreground" Value="Black"></Setter>
</Style>

</ResourceDictionary>
15 changes: 15 additions & 0 deletions darknet-demo-wpf-2/Skins/Skin.Common.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

<Style x:Key="labelStyleCommon" TargetType="Label">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>

<Style x:Key="checkBoxStyleCommon" TargetType="CheckBox">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Margin" Value="0,86,0,0" />
<Setter Property="VerticalAlignment" Value="Center" />
</Style>

</ResourceDictionary>
Loading