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 @@ + + + + + + + + + + +