diff --git a/DarkNet/WPF/ElementSkinManager.cs b/DarkNet/WPF/ElementSkinManager.cs
new file mode 100644
index 0000000..e6c2f40
--- /dev/null
+++ b/DarkNet/WPF/ElementSkinManager.cs
@@ -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;
+
+ ///
+ /// Create a new instance that uses the default instance.
+ ///
+ public ElementSkinManager(FrameworkElement element): this(DarkNet.Instance, element) { }
+
+ ///
+ /// Create a new instance that uses a custom instance.
+ ///
+ 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 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);
+ }
+ }
+
+ ///
+ /// Change the 's 's between the light and dark URIs which were set by
+ /// .
+ /// This is called once by , and again anytime you want to switch between themes for the control.
+ ///
+ /// to set dark theme, or to set light theme.
+ public virtual void UpdateTheme(bool isDarkTheme) {
+ if (_skinResources != null) {
+ _skinResources.Source = isDarkTheme ? _darkThemeResources : _lightThemeResources;
+ }
+ }
+
+ ///
+ /// Change the 's 's between the light and dark URIs which were set by
+ /// .
+ /// This is called once by , and again anytime you want to switch between themes for the control.
+ ///
+ /// to set dark theme, to set light theme, or to set current process theme
+ 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);
+ }
+
+}
diff --git a/darknet-demo-wpf-2/.editorconfig b/darknet-demo-wpf-2/.editorconfig
new file mode 100644
index 0000000..7fc29bf
--- /dev/null
+++ b/darknet-demo-wpf-2/.editorconfig
@@ -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
\ No newline at end of file
diff --git a/darknet-demo-wpf-2/App.xaml b/darknet-demo-wpf-2/App.xaml
new file mode 100644
index 0000000..2684f8f
--- /dev/null
+++ b/darknet-demo-wpf-2/App.xaml
@@ -0,0 +1,4 @@
+
+
diff --git a/darknet-demo-wpf-2/App.xaml.cs b/darknet-demo-wpf-2/App.xaml.cs
new file mode 100644
index 0000000..0ca5da0
--- /dev/null
+++ b/darknet-demo-wpf-2/App.xaml.cs
@@ -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();
+
+ }
+
+}
diff --git a/darknet-demo-wpf-2/AssemblyInfo.cs b/darknet-demo-wpf-2/AssemblyInfo.cs
new file mode 100644
index 0000000..8b5504e
--- /dev/null
+++ b/darknet-demo-wpf-2/AssemblyInfo.cs
@@ -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)
+)]
diff --git a/darknet-demo-wpf-2/MainWindow.xaml b/darknet-demo-wpf-2/MainWindow.xaml
new file mode 100644
index 0000000..c116ee2
--- /dev/null
+++ b/darknet-demo-wpf-2/MainWindow.xaml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/darknet-demo-wpf-2/MainWindow.xaml.cs b/darknet-demo-wpf-2/MainWindow.xaml.cs
new file mode 100644
index 0000000..b49dcd8
--- /dev/null
+++ b/darknet-demo-wpf-2/MainWindow.xaml.cs
@@ -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);
+ }
+
+}
diff --git a/darknet-demo-wpf-2/Properties/PublishProfiles/FolderProfile.pubxml b/darknet-demo-wpf-2/Properties/PublishProfiles/FolderProfile.pubxml
new file mode 100644
index 0000000..cb43b5b
--- /dev/null
+++ b/darknet-demo-wpf-2/Properties/PublishProfiles/FolderProfile.pubxml
@@ -0,0 +1,17 @@
+
+
+
+
+ Release
+ Any CPU
+ bin\Release\net6.0-windows\win-x64\publish\
+ FileSystem
+ net6.0-windows
+ win-x64
+ false
+ true
+ false
+
+
\ No newline at end of file
diff --git a/darknet-demo-wpf-2/Skins/Panel.Dark.xaml b/darknet-demo-wpf-2/Skins/Panel.Dark.xaml
new file mode 100644
index 0000000..115f7b6
--- /dev/null
+++ b/darknet-demo-wpf-2/Skins/Panel.Dark.xaml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
diff --git a/darknet-demo-wpf-2/Skins/Panel.Light.xaml b/darknet-demo-wpf-2/Skins/Panel.Light.xaml
new file mode 100644
index 0000000..b4da306
--- /dev/null
+++ b/darknet-demo-wpf-2/Skins/Panel.Light.xaml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
diff --git a/darknet-demo-wpf-2/Skins/Skin.Common.xaml b/darknet-demo-wpf-2/Skins/Skin.Common.xaml
new file mode 100644
index 0000000..c9f6c2a
--- /dev/null
+++ b/darknet-demo-wpf-2/Skins/Skin.Common.xaml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/darknet-demo-wpf-2/Skins/Skin.Dark.xaml b/darknet-demo-wpf-2/Skins/Skin.Dark.xaml
new file mode 100644
index 0000000..252c0e2
--- /dev/null
+++ b/darknet-demo-wpf-2/Skins/Skin.Dark.xaml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/darknet-demo-wpf-2/Skins/Skin.Light.xaml b/darknet-demo-wpf-2/Skins/Skin.Light.xaml
new file mode 100644
index 0000000..52c8bf7
--- /dev/null
+++ b/darknet-demo-wpf-2/Skins/Skin.Light.xaml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/darknet-demo-wpf-2/darknet-demo-wpf-2.csproj b/darknet-demo-wpf-2/darknet-demo-wpf-2.csproj
new file mode 100644
index 0000000..93698a0
--- /dev/null
+++ b/darknet-demo-wpf-2/darknet-demo-wpf-2.csproj
@@ -0,0 +1,53 @@
+
+
+
+ Exe
+ net6.0-windows
+ enable
+ true
+ darknet_demo_wpf_2
+ false
+ win-x64
+ icon.ico
+ major
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Code
+
+
+
+
+
+ Designer
+
+
+ MSBuild:Compile
+ Wpf
+ Designer
+
+
+ MSBuild:Compile
+ Wpf
+ Designer
+
+
+
+
diff --git a/darknet-demo-wpf-2/icon.ico b/darknet-demo-wpf-2/icon.ico
new file mode 100644
index 0000000..0e7c97f
Binary files /dev/null and b/darknet-demo-wpf-2/icon.ico differ
diff --git a/darknet-demo-wpf-2/icon.png b/darknet-demo-wpf-2/icon.png
new file mode 100644
index 0000000..b739de2
Binary files /dev/null and b/darknet-demo-wpf-2/icon.png differ
diff --git a/darknet.sln b/darknet.sln
index 3d11b9e..f0502cb 100644
--- a/darknet.sln
+++ b/darknet.sln
@@ -9,6 +9,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DarkNet", "darknet\DarkNet.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "darknet-demo-wpf", "darknet-demo-wpf\darknet-demo-wpf.csproj", "{93007D62-828D-48B7-AA61-3B2B6CD82981}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "darknet-demo-wpf-2", "darknet-demo-wpf-2\darknet-demo-wpf-2.csproj", "{FACA1473-B400-4C9E-8476-8C287B996E93}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -27,6 +29,10 @@ Global
{93007D62-828D-48B7-AA61-3B2B6CD82981}.Debug|Any CPU.Build.0 = Debug|Any CPU
{93007D62-828D-48B7-AA61-3B2B6CD82981}.Release|Any CPU.ActiveCfg = Release|Any CPU
{93007D62-828D-48B7-AA61-3B2B6CD82981}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FACA1473-B400-4C9E-8476-8C287B996E93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FACA1473-B400-4C9E-8476-8C287B996E93}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FACA1473-B400-4C9E-8476-8C287B996E93}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FACA1473-B400-4C9E-8476-8C287B996E93}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE