This commit is contained in:
GG Z
2025-08-24 13:49:55 +08:00
parent 785907d305
commit f37062be60
285 changed files with 4993 additions and 3377 deletions

6
Sample/App.config Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
</startup>
</configuration>

15
Sample/App.xaml Normal file
View File

@@ -0,0 +1,15 @@
<Application x:Class="Sample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Sample"
StartupUri="MainWindow.xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<!-- 启动时默认加载浅色主题 -->
<ResourceDictionary Source="/Themes/Light.xaml"/>
<ResourceDictionary Source="ButtonStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>

17
Sample/App.xaml.cs Normal file
View File

@@ -0,0 +1,17 @@
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
namespace Sample
{
/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
}
}

73
Sample/ButtonStyle.xaml Normal file
View File

@@ -0,0 +1,73 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Sample">
<!-- 确保这里的命名空间正确 -->
<!-- NeumorphicButton 的默认样式 -->
<Style TargetType="{x:Type Button}">
<!-- 基础属性设置 -->
<Setter Property="Background" Value="{DynamicResource AppBackgroundBrush}"/>
<Setter Property="Foreground" Value="{DynamicResource AppTextBrush}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Height" Value="50"/>
<Setter Property="MinWidth" Value="100"/>
<Setter Property="Padding" Value="15,5"/>
<Setter Property="HorizontalContentAlignment" Value="Center"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Cursor" Value="Hand"/>
<!-- 控件模板 -->
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<!-- 【关键修正】将不同状态的 Effect 定义为资源 -->
<ControlTemplate.Resources>
<!-- 正常状态的阴影 -->
<DropShadowEffect x:Key="NormalDarkShadow" ShadowDepth="4" Direction="315" Color="#000000" Opacity="0.15" BlurRadius="8"/>
<DropShadowEffect x:Key="NormalLightShadow" ShadowDepth="-4" Direction="135" Color="#FFFFFF" Opacity="0.7" BlurRadius="8"/>
<!-- 悬停状态的阴影 -->
<DropShadowEffect x:Key="HoverDarkShadow" ShadowDepth="6" Direction="315" Color="#000000" Opacity="0.15" BlurRadius="12"/>
<DropShadowEffect x:Key="HoverLightShadow" ShadowDepth="-6" Direction="135" Color="#FFFFFF" Opacity="0.7" BlurRadius="12"/>
<!-- 按下状态的阴影 (内阴影效果) -->
<DropShadowEffect x:Key="PressedDarkShadow" ShadowDepth="-3" Direction="135" Color="#FFFFFF" Opacity="0.6" BlurRadius="6"/>
<DropShadowEffect x:Key="PressedLightShadow" ShadowDepth="3" Direction="315" Color="#000000" Opacity="0.1" BlurRadius="6"/>
</ControlTemplate.Resources>
<!-- 视觉树 (Visual Tree) -->
<Border x:Name="RootBorder"
Background="{TemplateBinding Background}"
CornerRadius="12"
Effect="{StaticResource NormalDarkShadow}">
<!-- 应用默认的深色阴影 -->
<Grid x:Name="InnerGrid"
Effect="{StaticResource NormalLightShadow}">
<!-- 应用默认的亮色阴影 -->
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
Margin="{TemplateBinding Padding}"/>
</Grid>
</Border>
<!-- 【关键修正】触发器现在操作的是 Border 和 Grid 的 Effect 属性 -->
<ControlTemplate.Triggers>
<!-- 鼠标悬停时,替换整个 Effect 对象 -->
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="RootBorder" Property="Effect" Value="{StaticResource HoverDarkShadow}"/>
<Setter TargetName="InnerGrid" Property="Effect" Value="{StaticResource HoverLightShadow}"/>
</Trigger>
<!-- 鼠标按下时,替换成“内阴影”效果的 Effect 对象 -->
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="RootBorder" Property="Effect" Value="{StaticResource PressedDarkShadow}"/>
<Setter TargetName="InnerGrid" Property="Effect" Value="{StaticResource PressedLightShadow}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

View File

@@ -0,0 +1,137 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace Sample
{
public enum ThemeMode { Light, Dark }
/// <summary>
/// 一个优雅且绝对可靠的主题管理器。
/// 它通过一个明确的资源键列表,精确地对指定画刷进行平滑的过渡动画。
/// </summary>
public static class HybridThemeManager
{
// 【契约】我们回归到使用一个明确的、硬编码的列表。
// 这是最可靠的方式,它清晰地定义了哪些资源参与动画。
private static readonly List<string> AnimatableBrushKeys = new List<string>
{
//"AppBackgroundBrush",
//"AppTextBrush"
};
static HybridThemeManager()
{
var appResources = Application.Current.Resources;
foreach (var dict in appResources.MergedDictionaries)
{
var keys = dict.Keys;
//AnimatableBrushKeys.Clear();
AnimatableBrushKeys.AddRange(
keys.OfType<string>()
.Where(key => key.EndsWith("Brush") && dict[key] is SolidColorBrush)
);
}
//foreach (ResourceDictionary dict in appResources)
//{
//}
}
private static ThemeMode _currentMode = ThemeMode.Light;
private static bool _isSwitching = false;
public static async Task SwitchThemeAsync()
{
if (_isSwitching) return;
_isSwitching = true;
try
{
var targetMode = _currentMode == ThemeMode.Light ? ThemeMode.Dark : ThemeMode.Light;
var appResources = Application.Current.Resources;
// 步骤 1: “快照” - 根据【明确的列表】,记录当前颜色
var fromColors = TakeColorSnapshot(appResources);
// 步骤 2: “交换” - 替换资源字典
SwapThemeDictionary(appResources, targetMode);
// 步骤 3: “动画” - 对【明确的列表】中的画刷启动动画
await AnimateToNewTheme(appResources, fromColors);
_currentMode = targetMode;
}
finally
{
_isSwitching = false;
}
}
private static Dictionary<string, Color> TakeColorSnapshot(ResourceDictionary resources)
{
return AnimatableBrushKeys
.Where(key => resources.Contains(key) && resources[key] is SolidColorBrush)
.ToDictionary(key => key, key => ((SolidColorBrush)resources[key]).Color);
}
private static void SwapThemeDictionary(ResourceDictionary resources, ThemeMode targetMode)
{
var newThemeUri = new Uri($"/Themes/{targetMode}.xaml", UriKind.Relative);
var newThemeDict = new ResourceDictionary { Source = newThemeUri };
var oldDict = resources.MergedDictionaries.FirstOrDefault(d => d.Source?.OriginalString.Contains("/Themes/") ?? false);
if (oldDict != null)
{
resources.MergedDictionaries.Remove(oldDict);
}
resources.MergedDictionaries.Add(newThemeDict);
}
private static Task AnimateToNewTheme(ResourceDictionary resources, IReadOnlyDictionary<string, Color> fromColors)
{
var animationTasks = new List<Task>();
foreach (var key in AnimatableBrushKeys)
{
if (resources.Contains(key) && resources[key] is SolidColorBrush newBrush && fromColors.TryGetValue(key, out var fromColor))
{
// 【健壮性】依然保留对 StaticResource (冻结) 的处理
if (newBrush.IsFrozen)
{
newBrush = newBrush.Clone();
resources[key] = newBrush;
}
var toColor = newBrush.Color;
newBrush.Color = fromColor; // 伪装
animationTasks.Add(AnimateBrushColorAsync(newBrush, toColor));
}
}
return Task.WhenAll(animationTasks);
}
private static Task AnimateBrushColorAsync(SolidColorBrush brush, Color toColor)
{
var tcs = new TaskCompletionSource<bool>();
var animation = new ColorAnimation
{
From = brush.Color,
To = toColor,
Duration = TimeSpan.FromMilliseconds(400),
EasingFunction = new CubicEase { EasingMode = EasingMode.EaseOut }
};
animation.Completed += (s, e) =>
{
brush.BeginAnimation(SolidColorBrush.ColorProperty, null);
brush.Color = toColor;
tcs.TrySetResult(true);
};
brush.BeginAnimation(SolidColorBrush.ColorProperty, animation);
return tcs.Task;
}
}
}

27
Sample/MainWindow.xaml Normal file
View File

@@ -0,0 +1,27 @@
<Window
x:Class="Sample.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:local="clr-namespace:Sample"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Grid Background="{DynamicResource AppBackgroundBrush}">
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center">
<TextBlock
FontSize="24"
Foreground="{DynamicResource AppTextBrush}"
Text="背景和文字都会渐变" />
<Button
x:Name="SwitchThemeButton"
Margin="0,20,0,0"
Padding="15,8"
Click="SwitchThemeButton_Click"
Content="切换主题" />
</StackPanel>
</Grid>
</Window>

34
Sample/MainWindow.xaml.cs Normal file
View File

@@ -0,0 +1,34 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Sample
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private async void SwitchThemeButton_Click(object sender, RoutedEventArgs e)
{
SwitchThemeButton.IsEnabled = false;
await HybridThemeManager.SwitchThemeAsync();
SwitchThemeButton.IsEnabled = true;
}
}
}

View File

@@ -0,0 +1,52 @@
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
[assembly: AssemblyTitle("Sample")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Sample")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// 将 ComVisible 设置为 false 会使此程序集中的类型
//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
//请将此类型的 ComVisible 特性设置为 true。
[assembly: ComVisible(false)]
//若要开始生成可本地化的应用程序,请设置
//.csproj 文件中的 <UICulture>CultureYouAreCodingWith</UICulture>
//在 <PropertyGroup> 中。例如,如果你使用的是美国英语。
//使用的是美国英语,请将 <UICulture> 设置为 en-US。 然后取消
//对以下 NeutralResourceLanguage 特性的注释。 更新
//以下行中的“en-US”以匹配项目文件中的 UICulture 设置。
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //主题特定资源词典所处位置
//(未在页面中找到资源时使用,
//或应用程序资源字典中找到时使用)
ResourceDictionaryLocation.SourceAssembly //常规资源词典所处位置
//(未在页面中找到资源时使用,
//、应用程序或任何主题专用资源字典中找到时使用)
)]
// 程序集的版本信息由下列四个值组成:
//
// 主版本
// 次版本
// 生成号
// 修订号
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

71
Sample/Properties/Resources.Designer.cs generated Normal file
View File

@@ -0,0 +1,71 @@
//------------------------------------------------------------------------------
// <auto-generated>
// 此代码由工具生成。
// 运行时版本: 4.0.30319.42000
//
// 对此文件的更改可能导致不正确的行为,如果
// 重新生成代码,则所做更改将丢失。
// </auto-generated>
//------------------------------------------------------------------------------
namespace Sample.Properties
{
/// <summary>
/// 强类型资源类,用于查找本地化字符串等。
/// </summary>
// 此类是由 StronglyTypedResourceBuilder
// 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
// 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
// (以 /str 作为命令选项),或重新生成 VS 项目。
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Resources
{
private static global::System.Resources.ResourceManager resourceMan;
private static global::System.Globalization.CultureInfo resourceCulture;
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
internal Resources()
{
}
/// <summary>
/// 返回此类使用的缓存 ResourceManager 实例。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Resources.ResourceManager ResourceManager
{
get
{
if ((resourceMan == null))
{
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Sample.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
}
}
/// <summary>
/// 重写当前线程的 CurrentUICulture 属性,对
/// 使用此强类型资源类的所有资源查找执行重写。
/// </summary>
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
internal static global::System.Globalization.CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
}
}

View File

@@ -0,0 +1,117 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

30
Sample/Properties/Settings.Designer.cs generated Normal file
View File

@@ -0,0 +1,30 @@
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace Sample.Properties
{
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
{
private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
public static Settings Default
{
get
{
return defaultInstance;
}
}
}
}

View File

@@ -0,0 +1,7 @@
<?xml version='1.0' encoding='utf-8'?>
<SettingsFile xmlns="uri:settings" CurrentProfile="(Default)">
<Profiles>
<Profile Name="(Default)" />
</Profiles>
<Settings />
</SettingsFile>

111
Sample/Sample.csproj Normal file
View File

@@ -0,0 +1,111 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D24AA6E3-A990-4D58-B4F6-D78EB45D54AC}</ProjectGuid>
<OutputType>WinExe</OutputType>
<RootNamespace>Sample</RootNamespace>
<AssemblyName>Sample</AssemblyName>
<TargetFrameworkVersion>v4.6.2</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Data" />
<Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Xaml">
<RequiredTargetFramework>4.0</RequiredTargetFramework>
</Reference>
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</ApplicationDefinition>
<Compile Include="HybridThemeManager.cs" />
<Page Include="ButtonStyle.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="MainWindow.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Compile Include="App.xaml.cs">
<DependentUpon>App.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="MainWindow.xaml.cs">
<DependentUpon>MainWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Page Include="Themes\Dark.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Themes\Light.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs">
<SubType>Code</SubType>
</Compile>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTime>True</DesignTime>
<DependentUpon>Resources.resx</DependentUpon>
</Compile>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource>
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

9
Sample/Themes/Dark.xaml Normal file
View File

@@ -0,0 +1,9 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- 深色主题 -->
<Color x:Key="BackgroundColor">#222222</Color>
<Color x:Key="ForegroundColor">#DDDDDD</Color>
<SolidColorBrush x:Key="AppBackgroundBrush" Color="{DynamicResource BackgroundColor}"/>
<SolidColorBrush x:Key="AppTextBrush" Color="{DynamicResource ForegroundColor}"/>
</ResourceDictionary>

11
Sample/Themes/Light.xaml Normal file
View File

@@ -0,0 +1,11 @@
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- 浅色主题 -->
<Color x:Key="BackgroundColor">#EEEEEE</Color>
<Color x:Key="ForegroundColor">#111111</Color>
<SolidColorBrush x:Key="AppBackgroundBrush" Color="{DynamicResource BackgroundColor}"/>
<SolidColorBrush x:Key="AppTextBrush" Color="{DynamicResource ForegroundColor}"/>
</ResourceDictionary>