完善标题栏皮肤颜色切换

This commit is contained in:
ww-rm
2025-10-03 23:45:35 +08:00
parent 1f6e19e544
commit c9730e1a11
13 changed files with 166 additions and 19 deletions

View File

@@ -1,6 +1,7 @@
using Microsoft.Win32; using Microsoft.Win32;
using NLog; using NLog;
using SpineViewer.Natives; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.ViewModels.MainWindow; using SpineViewer.ViewModels.MainWindow;
using SpineViewer.Views; using SpineViewer.Views;
using System.Collections.Frozen; using System.Collections.Frozen;
@@ -12,6 +13,7 @@ using System.IO;
using System.IO.Pipes; using System.IO.Pipes;
using System.Reflection; using System.Reflection;
using System.Windows; using System.Windows;
using System.Windows.Interop;
namespace SpineViewer namespace SpineViewer
{ {
@@ -231,8 +233,8 @@ namespace SpineViewer
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to query autorun registry key, {0}", ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to query autorun registry key, {0}", ex.Message);
return false; return false;
} }
} }
@@ -259,8 +261,8 @@ namespace SpineViewer
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to set autorun registry key, {0}", ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to set autorun registry key, {0}", ex.Message);
} }
} }
} }
@@ -343,8 +345,8 @@ namespace SpineViewer
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to switch language to {0}, {1}", value, ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to switch language to {0}, {1}", value, ex.Message);
} }
} }
} }
@@ -360,17 +362,19 @@ namespace SpineViewer
{ {
Resources.MergedDictionaries.Add(new() { Source = new(uri, UriKind.Relative) }); Resources.MergedDictionaries.Add(new() { Source = new(uri, UriKind.Relative) });
Resources.MergedDictionaries.Add(new() { Source = new("Resources/Theme.xaml", UriKind.Relative) }); Resources.MergedDictionaries.Add(new() { Source = new("Resources/Theme.xaml", UriKind.Relative) });
var hwnd = new WindowInteropHelper(Current.MainWindow).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
_skin = value; _skin = value;
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to switch skin to {0}, {1}", value, ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to switch skin to {0}, {1}", value, ex.Message);
} }
} }
} }
private AppSkin _skin = AppSkin.Light; private AppSkin _skin = AppSkin.Light;
} }
public enum AppLanguage public enum AppLanguage

View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
namespace SpineViewer.Natives
{
/// <summary>
/// dwmapi.dll 包装类
/// </summary>
public static class Dwmapi
{
private const uint DWMWA_USE_IMMERSIVE_DARK_MODE = 20;
private const uint DWMWA_CAPTION_COLOR = 35;
private const uint DWMWA_TEXT_COLOR = 36;
private const uint DWMWA_COLOR_DEFAULT = 0xFFFFFFFF;
[DllImport("dwmapi.dll")]
private static extern int DwmSetWindowAttribute(IntPtr hwnd, uint dwAttribute, ref int pvAttribute, int cbAttribute);
[DllImport("dwmapi.dll")]
private static extern int DwmSetWindowAttribute(IntPtr hwnd, uint dwAttribute, ref uint pvAttribute, int cbAttribute);
public static bool SetWindowCaptionColor(IntPtr hwnd, Color color)
{
int c = color.R | (color.G << 8) | (color.B << 16);
return 0 == DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, ref c, sizeof(uint));
}
public static bool SetWindowTextColor(IntPtr hwnd, Color color)
{
int c = color.R | (color.G << 8) | (color.B << 16);
return 0 == DwmSetWindowAttribute(hwnd, DWMWA_TEXT_COLOR, ref c, sizeof(uint));
}
public static bool SetWindowDarkMode(IntPtr hwnd, bool darkMode)
{
int b = darkMode ? 1 : 0;
uint c = DWMWA_COLOR_DEFAULT;
DwmSetWindowAttribute(hwnd, DWMWA_CAPTION_COLOR, ref c, sizeof(uint));
DwmSetWindowAttribute(hwnd, DWMWA_TEXT_COLOR, ref c, sizeof(uint));
return 0 == DwmSetWindowAttribute(hwnd, DWMWA_USE_IMMERSIVE_DARK_MODE, ref b, sizeof(int));
}
}
}

View File

@@ -66,8 +66,8 @@ namespace SpineViewer.Utils
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to read json file {0}, {1}", path, ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to read json file {0}, {1}", path, ex.Message);
MessagePopupService.Error($"Failed to read json file {path}, {ex.ToString()}"); MessagePopupService.Error($"Failed to read json file {path}, {ex.ToString()}");
} }
} }
@@ -88,8 +88,8 @@ namespace SpineViewer.Utils
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to save json file {0}, {1}", path, ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to save json file {0}, {1}", path, ex.Message);
MessagePopupService.Error($"Failed to save json file {path}, {ex.ToString()}"); MessagePopupService.Error($"Failed to save json file {path}, {ex.ToString()}");
return false; return false;
} }

View File

@@ -218,8 +218,8 @@ namespace SpineViewer.ViewModels.MainWindow
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.Error("Failed to reload spine {0}, {1}", sp.SkelPath, ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to reload spine {0}, {1}", sp.SkelPath, ex.Message);
} }
} }
} }
@@ -279,8 +279,8 @@ namespace SpineViewer.ViewModels.MainWindow
catch (Exception ex) catch (Exception ex)
{ {
error++; error++;
_logger.Error("Failed to reload spine {0}, {1}", sp.SkelPath, ex.Message);
_logger.Trace(ex.ToString()); _logger.Trace(ex.ToString());
_logger.Error("Failed to reload spine {0}, {1}", sp.SkelPath, ex.Message);
} }
} }
} }

View File

@@ -1,4 +1,6 @@
using System; using SpineViewer.Natives;
using SpineViewer.Resources;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -8,6 +10,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -22,6 +25,14 @@ namespace SpineViewer.Views
public AboutDialog() public AboutDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += AboutDialog_SourceInitialized;
}
private void AboutDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
} }
} }

View File

@@ -1,4 +1,6 @@
using System; using SpineViewer.Natives;
using SpineViewer.Resources;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
@@ -8,6 +10,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -22,6 +25,14 @@ namespace SpineViewer.Views
public DiagnosticsDialog() public DiagnosticsDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += DiagnosticsDialog_SourceInitialized;
}
private void DiagnosticsDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
} }
} }

View File

@@ -1,4 +1,6 @@
using SpineViewer.Services; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.Services;
using SpineViewer.ViewModels.Exporters; using SpineViewer.ViewModels.Exporters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -10,6 +12,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -24,6 +27,14 @@ namespace SpineViewer.Views.ExporterDialogs
public CustomFFmpegExporterDialog() public CustomFFmpegExporterDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += CustomFFmpegExporterDialog_SourceInitialized;
}
private void CustomFFmpegExporterDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
private void ButtonOK_Click(object sender, RoutedEventArgs e) private void ButtonOK_Click(object sender, RoutedEventArgs e)

View File

@@ -1,4 +1,6 @@
using SpineViewer.Services; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.Services;
using SpineViewer.ViewModels.Exporters; using SpineViewer.ViewModels.Exporters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -10,6 +12,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -24,6 +27,14 @@ namespace SpineViewer.Views.ExporterDialogs
public FFmpegVideoExporterDialog() public FFmpegVideoExporterDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += FFmpegVideoExporterDialog_SourceInitialized;
}
private void FFmpegVideoExporterDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
private void ButtonOK_Click(object sender, RoutedEventArgs e) private void ButtonOK_Click(object sender, RoutedEventArgs e)

View File

@@ -1,4 +1,6 @@
using SpineViewer.Services; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.Services;
using SpineViewer.ViewModels.Exporters; using SpineViewer.ViewModels.Exporters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -10,6 +12,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -24,6 +27,14 @@ namespace SpineViewer.Views.ExporterDialogs
public FrameExporterDialog() public FrameExporterDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += FrameExporterDialog_SourceInitialized;
}
private void FrameExporterDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
private void ButtonOK_Click(object sender, RoutedEventArgs e) private void ButtonOK_Click(object sender, RoutedEventArgs e)

View File

@@ -1,4 +1,6 @@
using SpineViewer.Services; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.Services;
using SpineViewer.ViewModels.Exporters; using SpineViewer.ViewModels.Exporters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -10,6 +12,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -24,6 +27,14 @@ namespace SpineViewer.Views.ExporterDialogs
public FrameSequenceExporterDialog() public FrameSequenceExporterDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += FrameSequenceExporterDialog_SourceInitialized;
}
private void FrameSequenceExporterDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
private void ButtonOK_Click(object sender, RoutedEventArgs e) private void ButtonOK_Click(object sender, RoutedEventArgs e)

View File

@@ -15,6 +15,7 @@ using System.ComponentModel;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Reflection.Metadata; using System.Reflection.Metadata;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using System.Windows; using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
@@ -65,11 +66,11 @@ public partial class MainWindow : Window
// XXX: hc 的 NotifyIcon 的 Text 似乎没法双向绑定 // XXX: hc 的 NotifyIcon 的 Text 似乎没法双向绑定
_notifyIcon.Text = _vm.Title; _notifyIcon.Text = _vm.Title;
SourceInitialized += MainWindow_SourceInitialized;
Loaded += MainWindow_Loaded; Loaded += MainWindow_Loaded;
ContentRendered += MainWindow_ContentRendered; ContentRendered += MainWindow_ContentRendered;
Closing += MainWindow_Closing; Closing += MainWindow_Closing;
Closed += MainWindow_Closed; Closed += MainWindow_Closed;
_vm.SpineObjectListViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging; _vm.SpineObjectListViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
_vm.SFMLRendererViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging; _vm.SFMLRendererViewModel.RequestSelectionChanging += SpinesListView_RequestSelectionChanging;
@@ -178,6 +179,13 @@ public partial class MainWindow : Window
#region MainWindow #region MainWindow
private void MainWindow_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
}
private void MainWindow_Loaded(object sender, RoutedEventArgs e) private void MainWindow_Loaded(object sender, RoutedEventArgs e)
{ {
var vm = _vm.SFMLRendererViewModel; var vm = _vm.SFMLRendererViewModel;
@@ -728,6 +736,7 @@ public partial class MainWindow : Window
} }
#endregion #endregion
private void DebugMenuItem_Click(object sender, RoutedEventArgs e) private void DebugMenuItem_Click(object sender, RoutedEventArgs e)
{ {
@@ -737,7 +746,6 @@ public partial class MainWindow : Window
_logger.Warn("Warn"); _logger.Warn("Warn");
_logger.Error("Error"); _logger.Error("Error");
_logger.Fatal("Fatal"); _logger.Fatal("Fatal");
return; return;
#endif #endif
} }

View File

@@ -1,4 +1,6 @@
using SpineViewer.Services; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.Services;
using SpineViewer.ViewModels.Exporters; using SpineViewer.ViewModels.Exporters;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
@@ -10,6 +12,7 @@ using System.Windows.Controls;
using System.Windows.Data; using System.Windows.Data;
using System.Windows.Documents; using System.Windows.Documents;
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using System.Windows.Shapes; using System.Windows.Shapes;
@@ -24,6 +27,14 @@ namespace SpineViewer.Views
public PreferenceDialog() public PreferenceDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += PreferenceDialog_SourceInitialized;
}
private void PreferenceDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
} }
private void ButtonOK_Click(object sender, RoutedEventArgs e) private void ButtonOK_Click(object sender, RoutedEventArgs e)

View File

@@ -1,4 +1,6 @@
using SpineViewer.ViewModels; using SpineViewer.Natives;
using SpineViewer.Resources;
using SpineViewer.ViewModels;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@@ -25,9 +27,17 @@ namespace SpineViewer.Views
public ProgressDialog() public ProgressDialog()
{ {
InitializeComponent(); InitializeComponent();
SourceInitialized += ProgressDialog_SourceInitialized;
Loaded += ProgressWindow_Loaded; Loaded += ProgressWindow_Loaded;
} }
private void ProgressDialog_SourceInitialized(object? sender, EventArgs e)
{
var hwnd = new WindowInteropHelper(this).Handle;
Dwmapi.SetWindowTextColor(hwnd, AppResource.Color_PrimaryText);
Dwmapi.SetWindowCaptionColor(hwnd, AppResource.Color_Region);
}
private void ProgressWindow_Loaded(object sender, RoutedEventArgs e) private void ProgressWindow_Loaded(object sender, RoutedEventArgs e)
{ {
var hwnd = new WindowInteropHelper(this).Handle; var hwnd = new WindowInteropHelper(this).Handle;