fix: 修复启动隐藏与深色主题界面问题

修复托盘退出卡死、启动隐藏闪窗和隐藏实例再次启动无法唤醒的问题。

统一深色主题资源与控件模板,补齐卡片、内置图标、右键菜单和弹窗背景样式。

验证:dotnet build PersonalToolbox.sln;dotnet run --project tests\PersonalToolbox.Tests\PersonalToolbox.Tests.csproj。
This commit is contained in:
2026-05-27 17:43:22 +08:00
parent bbc183cef6
commit 3909764972
14 changed files with 720 additions and 152 deletions

View File

@@ -1,14 +1,14 @@
<Application x:Class="PersonalToolbox.App"
<Application x:Class="PersonalToolbox.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:views="clr-namespace:PersonalToolbox.Views"
StartupUri="MainWindow.xaml">
xmlns:views="clr-namespace:PersonalToolbox.Views">
<Application.Resources>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
<views:IconKeyToTextConverter x:Key="IconKeyToTextConverter" />
<SolidColorBrush x:Key="AppBackgroundBrush" Color="#F7F8FA" />
<SolidColorBrush x:Key="PanelBackgroundBrush" Color="#FFFFFF" />
<SolidColorBrush x:Key="CardBackgroundBrush" Color="#FBFCFE" />
<SolidColorBrush x:Key="SelectedCardBackgroundBrush" Color="#EFF5FF" />
<SolidColorBrush x:Key="BadgeBackgroundBrush" Color="#EDF2F7" />
<SolidColorBrush x:Key="IconBackgroundBrush" Color="#E8F0FF" />
<SolidColorBrush x:Key="BorderBrushSoft" Color="#D9DEE7" />
@@ -16,23 +16,344 @@
<SolidColorBrush x:Key="PrimaryTextBrush" Color="#172033" />
<SolidColorBrush x:Key="SecondaryTextBrush" Color="#5C667A" />
<Style TargetType="Window">
<Setter Property="Background" Value="{DynamicResource AppBackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
</Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
</Style>
<Style TargetType="CheckBox">
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="VerticalContentAlignment" Value="Center" />
</Style>
<Style TargetType="Button">
<Setter Property="MinHeight" Value="32" />
<Setter Property="Padding" Value="12,4" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="Background" Value="{DynamicResource PanelBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrushSoft}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="ButtonBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter Margin="{TemplateBinding Padding}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
RecognizesAccessKey="True" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ButtonBorder" Property="BorderBrush" Value="{DynamicResource PrimaryBrush}" />
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="True">
<Setter TargetName="ButtonBorder" Property="BorderBrush" Value="{DynamicResource PrimaryBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.55" />
<Setter Property="Foreground" Value="{DynamicResource SecondaryTextBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TextBox">
<Setter Property="Padding" Value="8,4" />
<Setter Property="MinHeight" Value="32" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="CaretBrush" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="SelectionBrush" Value="{DynamicResource PrimaryBrush}" />
<Setter Property="Background" Value="{DynamicResource PanelBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrushSoft}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border x:Name="TextBoxBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ScrollViewer x:Name="PART_ContentHost"
Margin="{TemplateBinding Padding}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter TargetName="TextBoxBorder" Property="BorderBrush" Value="{DynamicResource PrimaryBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.55" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ComboBoxItem">
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="Background" Value="{DynamicResource PanelBackgroundBrush}" />
<Setter Property="Padding" Value="8,5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBoxItem">
<Border x:Name="ItemBorder"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="ItemBorder" Property="Background" Value="{DynamicResource SelectedCardBackgroundBrush}" />
</Trigger>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="ItemBorder" Property="Background" Value="{DynamicResource SelectedCardBackgroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ComboBox">
<Setter Property="Padding" Value="8,4" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="MinHeight" Value="32" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="Background" Value="{DynamicResource PanelBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrushSoft}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ComboBox">
<Grid>
<Border x:Name="ComboBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Grid>
<ContentPresenter x:Name="ContentSite"
Margin="{TemplateBinding Padding}"
HorizontalAlignment="Left"
VerticalAlignment="Center"
IsHitTestVisible="False"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" />
<Path Data="M 0 0 L 4 4 L 8 0 Z"
Fill="{DynamicResource SecondaryTextBrush}"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Margin="0,0,10,0" />
<ToggleButton Background="Transparent"
BorderThickness="0"
Focusable="False"
Opacity="0"
IsChecked="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
ClickMode="Press" />
</Grid>
</Border>
<Popup x:Name="PART_Popup"
AllowsTransparency="True"
Focusable="False"
IsOpen="{TemplateBinding IsDropDownOpen}"
Placement="Bottom"
PopupAnimation="Fade">
<Border Background="{DynamicResource PanelBackgroundBrush}"
BorderBrush="{DynamicResource BorderBrushSoft}"
BorderThickness="1"
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource TemplatedParent}}"
MaxHeight="{TemplateBinding MaxDropDownHeight}">
<ScrollViewer>
<ItemsPresenter />
</ScrollViewer>
</Border>
</Popup>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsKeyboardFocusWithin" Value="True">
<Setter TargetName="ComboBorder" Property="BorderBrush" Value="{DynamicResource PrimaryBrush}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="ComboBorder" Property="BorderBrush" Value="{DynamicResource PrimaryBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.55" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="TabControl">
<Setter Property="Background" Value="{DynamicResource AppBackgroundBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrushSoft}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
</Style>
<Style TargetType="TabItem">
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="Padding" Value="10,5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TabItem">
<Grid>
<Border x:Name="TabBorder"
Background="{DynamicResource PanelBackgroundBrush}"
BorderBrush="{DynamicResource BorderBrushSoft}"
BorderThickness="1,1,1,0"
Padding="{TemplateBinding Padding}">
<ContentPresenter ContentSource="Header"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="TabBorder" Property="Background" Value="{DynamicResource SelectedCardBackgroundBrush}" />
<Setter TargetName="TabBorder" Property="BorderBrush" Value="{DynamicResource PrimaryBrush}" />
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="TabBorder" Property="BorderBrush" Value="{DynamicResource PrimaryBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="DataGrid">
<Setter Property="Background" Value="{DynamicResource PanelBackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrushSoft}" />
<Setter Property="GridLinesVisibility" Value="Horizontal" />
<Setter Property="HorizontalGridLinesBrush" Value="{DynamicResource BorderBrushSoft}" />
<Setter Property="VerticalGridLinesBrush" Value="{DynamicResource BorderBrushSoft}" />
<Setter Property="RowBackground" Value="{DynamicResource PanelBackgroundBrush}" />
<Setter Property="AlternatingRowBackground" Value="{DynamicResource CardBackgroundBrush}" />
</Style>
<Style TargetType="DataGridColumnHeader">
<Setter Property="Background" Value="{DynamicResource CardBackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrushSoft}" />
<Setter Property="Padding" Value="8,6" />
</Style>
<Style TargetType="DataGridRow">
<Setter Property="Background" Value="{DynamicResource PanelBackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
</Style>
<Style TargetType="DataGridCell">
<Setter Property="Background" Value="Transparent" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrushSoft}" />
<Setter Property="Padding" Value="6,4" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="{DynamicResource SelectedCardBackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="ContextMenu">
<Setter Property="Background" Value="{DynamicResource PanelBackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrushSoft}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="4" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContextMenu">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<StackPanel IsItemsHost="True"
KeyboardNavigation.DirectionalNavigation="Cycle" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="MenuItem">
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="Padding" Value="12,7" />
<Setter Property="MinWidth" Value="180" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MenuItem">
<Border x:Name="MenuItemBorder"
Background="{TemplateBinding Background}"
Padding="{TemplateBinding Padding}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<ContentPresenter ContentSource="Header"
RecognizesAccessKey="True"
VerticalAlignment="Center" />
<TextBlock Grid.Column="1"
Text="{TemplateBinding InputGestureText}"
Margin="24,0,0,0"
Foreground="{DynamicResource SecondaryTextBrush}"
VerticalAlignment="Center" />
</Grid>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsHighlighted" Value="True">
<Setter TargetName="MenuItemBorder" Property="Background" Value="{DynamicResource SelectedCardBackgroundBrush}" />
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Opacity" Value="0.45" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="ListBox">
<Setter Property="Background" Value="{DynamicResource PanelBackgroundBrush}" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrushSoft}" />
</Style>
<Style TargetType="ListBoxItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="Foreground" Value="{DynamicResource PrimaryTextBrush}" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="ItemBorder"
Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="ItemBorder" Property="Background" Value="{DynamicResource SelectedCardBackgroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>

View File

@@ -1,6 +1,10 @@
using System.Configuration;
using System.Data;
using System.IO;
using System.IO.Pipes;
using System.Text;
using System.Windows;
using System.Threading;
namespace PersonalToolbox;
@@ -9,5 +13,136 @@ namespace PersonalToolbox;
/// </summary>
public partial class App : System.Windows.Application
{
private const string ActivatePipeName = "PersonalToolbox.Activate";
private FileStream? _instanceLockFile;
private CancellationTokenSource? _activationPipeCancellation;
private MainWindow? _mainWindow;
protected override async void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
ShutdownMode = ShutdownMode.OnExplicitShutdown;
if (!TryAcquireInstanceLock())
{
SignalExistingInstance();
Environment.Exit(0);
return;
}
var mainWindow = new MainWindow();
_mainWindow = mainWindow;
MainWindow = mainWindow;
StartActivationPipe();
await mainWindow.InitializeShellAsync();
if (!mainWindow.StartHiddenToTray)
{
mainWindow.ShowMainWindow();
}
else
{
mainWindow.RefreshTrayMenu();
}
await mainWindow.RunStartupTasksAsync();
}
protected override void OnExit(ExitEventArgs e)
{
_activationPipeCancellation?.Cancel();
_activationPipeCancellation?.Dispose();
_instanceLockFile?.Dispose();
base.OnExit(e);
}
private bool TryAcquireInstanceLock()
{
try
{
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var configDirectory = Path.Combine(appData, "PersonalToolbox");
Directory.CreateDirectory(configDirectory);
var lockPath = Path.Combine(configDirectory, "PersonalToolbox.lock");
_instanceLockFile = new FileStream(lockPath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None);
_instanceLockFile.SetLength(0);
var processId = Encoding.UTF8.GetBytes(Environment.ProcessId.ToString());
_instanceLockFile.Write(processId, 0, processId.Length);
_instanceLockFile.Flush();
return true;
}
catch (IOException)
{
return false;
}
catch (UnauthorizedAccessException)
{
return false;
}
}
private static void SignalExistingInstance()
{
for (var attempt = 0; attempt < 3; attempt++)
{
try
{
using var pipe = new NamedPipeClientStream(".", ActivatePipeName, PipeDirection.Out);
pipe.Connect(800);
using var writer = new StreamWriter(pipe, Encoding.UTF8)
{
AutoFlush = true
};
writer.WriteLine("show");
return;
}
catch (IOException)
{
}
catch (TimeoutException)
{
}
Thread.Sleep(150);
}
}
private void StartActivationPipe()
{
_activationPipeCancellation = new CancellationTokenSource();
_ = Task.Run(() => ListenForActivationAsync(_activationPipeCancellation.Token));
}
private async Task ListenForActivationAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
try
{
await using var pipe = new NamedPipeServerStream(
ActivatePipeName,
PipeDirection.In,
1,
PipeTransmissionMode.Byte,
PipeOptions.Asynchronous);
await pipe.WaitForConnectionAsync(cancellationToken);
using var reader = new StreamReader(pipe, Encoding.UTF8);
_ = await reader.ReadLineAsync(cancellationToken);
await Dispatcher.BeginInvoke(() => _mainWindow?.ShowMainWindow());
}
catch (OperationCanceledException)
{
return;
}
catch (IOException)
{
}
}
}
}

View File

@@ -1,4 +1,4 @@
<Window x:Class="PersonalToolbox.MainWindow"
<Window x:Class="PersonalToolbox.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"
@@ -10,8 +10,7 @@
Width="1120"
MinHeight="620"
MinWidth="960"
Background="{StaticResource AppBackgroundBrush}"
Loaded="Window_OnLoaded"
Background="{DynamicResource AppBackgroundBrush}"
Closing="Window_OnClosing">
<Grid x:Name="RootGrid" Margin="16">
<Grid.RowDefinitions>
@@ -20,8 +19,8 @@
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Background="{StaticResource PanelBackgroundBrush}"
BorderBrush="{StaticResource BorderBrushSoft}"
<Border Background="{DynamicResource PanelBackgroundBrush}"
BorderBrush="{DynamicResource BorderBrushSoft}"
BorderThickness="1"
CornerRadius="8"
Padding="12">
@@ -78,8 +77,8 @@
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Border Background="{StaticResource PanelBackgroundBrush}"
BorderBrush="{StaticResource BorderBrushSoft}"
<Border Background="{DynamicResource PanelBackgroundBrush}"
BorderBrush="{DynamicResource BorderBrushSoft}"
BorderThickness="1"
CornerRadius="8"
Padding="12">
@@ -93,7 +92,7 @@
<TextBlock Text="分类"
FontSize="16"
FontWeight="SemiBold"
Foreground="{StaticResource PrimaryTextBrush}"
Foreground="{DynamicResource PrimaryTextBrush}"
ToolTip="一级分类列表,工具只能属于一个分类。" />
<ListBox Grid.Row="1"
@@ -112,14 +111,14 @@
<Border Width="32"
Height="26"
CornerRadius="6"
Background="{StaticResource IconBackgroundBrush}"
Background="{DynamicResource IconBackgroundBrush}"
DockPanel.Dock="Left">
<TextBlock Text="{Binding IconKey, Converter={StaticResource IconKeyToTextConverter}}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="11"
FontWeight="SemiBold"
Foreground="{StaticResource PrimaryBrush}" />
FontFamily="Segoe MDL2 Assets"
FontSize="16"
Foreground="{DynamicResource PrimaryBrush}" />
</Border>
<TextBlock Text="{Binding Name}"
Padding="8,7"
@@ -151,8 +150,8 @@
</Border>
<Border Grid.Column="2"
Background="{StaticResource PanelBackgroundBrush}"
BorderBrush="{StaticResource BorderBrushSoft}"
Background="{DynamicResource PanelBackgroundBrush}"
BorderBrush="{DynamicResource BorderBrushSoft}"
BorderThickness="1"
CornerRadius="8"
Padding="12">
@@ -179,12 +178,23 @@
<Border Width="{Binding CardWidth}"
Height="{Binding CardHeight}"
Margin="6"
Padding="12"
Padding="14"
CornerRadius="8"
BorderThickness="1"
BorderBrush="{StaticResource BorderBrushSoft}"
Background="{StaticResource CardBackgroundBrush}"
Cursor="Hand"
ToolTip="{Binding DetailText}">
<Border.Style>
<Style TargetType="Border">
<Setter Property="BorderBrush" Value="{DynamicResource BorderBrushSoft}" />
<Setter Property="Background" Value="{DynamicResource CardBackgroundBrush}" />
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListBoxItem}}" Value="True">
<Setter Property="BorderBrush" Value="{DynamicResource PrimaryBrush}" />
<Setter Property="Background" Value="{DynamicResource SelectedCardBackgroundBrush}" />
</DataTrigger>
</Style.Triggers>
</Style>
</Border.Style>
<Border.ContextMenu>
<ContextMenu DataContext="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="启动"
@@ -216,22 +226,26 @@
</Border.ContextMenu>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<DockPanel>
<Border Width="42"
Height="32"
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Border Width="60"
Height="60"
CornerRadius="6"
Background="{StaticResource IconBackgroundBrush}"
DockPanel.Dock="Left"
Background="{DynamicResource IconBackgroundBrush}"
ToolTip="工具图标,可来自自动缓存、内置图标库或本地图片。">
<Grid>
<Image Source="{Binding IconImagePath}"
Margin="4"
Margin="6"
Stretch="Uniform">
<Image.Style>
<Style TargetType="Image">
@@ -247,8 +261,9 @@
<TextBlock Text="{Binding IconText}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="SemiBold"
Foreground="{StaticResource PrimaryBrush}">
FontFamily="Segoe MDL2 Assets"
FontSize="30"
Foreground="{DynamicResource PrimaryBrush}">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Visible" />
@@ -262,26 +277,41 @@
</TextBlock>
</Grid>
</Border>
<TextBlock Text="{Binding TypeLabel}"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Foreground="{StaticResource SecondaryTextBrush}"
ToolTip="工具类型标记。" />
</DockPanel>
<StackPanel Grid.Column="1"
Margin="12,2,8,0">
<TextBlock Text="{Binding Name}"
FontSize="16"
FontWeight="SemiBold"
Foreground="{DynamicResource PrimaryTextBrush}"
TextTrimming="CharacterEllipsis"
ToolTip="{Binding Name}" />
<TextBlock Text="{Binding CategoryName}"
Margin="0,6,0,0"
Foreground="{DynamicResource SecondaryTextBrush}"
TextTrimming="CharacterEllipsis"
ToolTip="{Binding CategoryName}" />
</StackPanel>
<Border Grid.Column="2"
MinWidth="44"
Height="24"
Padding="8,2"
CornerRadius="4"
Background="{DynamicResource BadgeBackgroundBrush}"
ToolTip="工具类型标记。">
<TextBlock Text="{Binding TypeLabel}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="12"
Foreground="{DynamicResource SecondaryTextBrush}" />
</Border>
</Grid>
<TextBlock Grid.Row="1"
Text="{Binding Name}"
Margin="0,10,0,0"
FontSize="15"
FontWeight="SemiBold"
Foreground="{StaticResource PrimaryTextBrush}"
TextTrimming="CharacterEllipsis"
ToolTip="{Binding Name}" />
<TextBlock Grid.Row="2"
Text="{Binding Description}"
Margin="0,6,0,0"
Foreground="{StaticResource SecondaryTextBrush}"
Margin="0,10,0,0"
Foreground="{DynamicResource SecondaryTextBrush}"
TextWrapping="Wrap"
TextTrimming="CharacterEllipsis"
ToolTip="{Binding Description}">
@@ -297,7 +327,7 @@
</TextBlock.Style>
</TextBlock>
<ItemsControl Grid.Row="3"
<ItemsControl Grid.Row="2"
ItemsSource="{Binding StatusBadges}"
Margin="0,8,0,0"
ToolTip="状态标记:路径失效、快捷键、自动运行或管理员。">
@@ -308,13 +338,13 @@
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="{StaticResource BadgeBackgroundBrush}"
<Border Background="{DynamicResource BadgeBackgroundBrush}"
CornerRadius="4"
Padding="5,2"
Margin="0,0,5,4">
<TextBlock Text="{Binding}"
FontSize="11"
Foreground="{StaticResource SecondaryTextBrush}" />
Foreground="{DynamicResource SecondaryTextBrush}" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
@@ -331,8 +361,8 @@
Header="底部信息"
IsExpanded="{Binding IsLogPanelExpanded}"
ToolTip="显示启动、组合、自动运行、导入导出和错误信息。">
<Border Background="{StaticResource PanelBackgroundBrush}"
BorderBrush="{StaticResource BorderBrushSoft}"
<Border Background="{DynamicResource PanelBackgroundBrush}"
BorderBrush="{DynamicResource BorderBrushSoft}"
BorderThickness="1"
CornerRadius="8"
Padding="10"

View File

@@ -2,6 +2,7 @@ using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using PersonalToolbox.Models;
using PersonalToolbox.Services;
@@ -17,6 +18,8 @@ public partial class MainWindow : Window
private TrayService? _trayService;
private bool _initialized;
private bool _exitRequested;
private bool _isShuttingDown;
private bool _cleanupCompleted;
private System.Windows.Point _dragStartPoint;
public MainWindow()
@@ -28,7 +31,9 @@ public partial class MainWindow : Window
DataContext = _viewModel;
}
private async void Window_OnLoaded(object sender, RoutedEventArgs e)
public bool StartHiddenToTray => _viewModel.Data.Settings.StartHiddenToTray;
public async Task InitializeShellAsync()
{
if (_initialized)
{
@@ -41,6 +46,7 @@ public partial class MainWindow : Window
Width = _viewModel.Data.Settings.MainWindowWidth;
Height = _viewModel.Data.Settings.MainWindowHeight;
new WindowInteropHelper(this).EnsureHandle();
_trayService = new TrayService(
this,
@@ -50,18 +56,32 @@ public partial class MainWindow : Window
RequestExit);
RegisterHotkeys();
}
if (_viewModel.Data.Settings.StartHiddenToTray)
{
Hide();
_trayService.RefreshMenuText();
}
public async Task RunStartupTasksAsync()
{
await _viewModel.RunAutoRunAsync();
}
private void Window_OnClosing(object? sender, CancelEventArgs e)
public void ShowMainWindow()
{
Show();
Activate();
RefreshTrayMenu();
}
public void RefreshTrayMenu()
{
_trayService?.RefreshMenuText();
}
private async void Window_OnClosing(object? sender, CancelEventArgs e)
{
if (_cleanupCompleted)
{
return;
}
if (!_exitRequested && _viewModel.Data.Settings.HideOnClose)
{
e.Cancel = true;
@@ -70,11 +90,8 @@ public partial class MainWindow : Window
return;
}
_viewModel.Data.Settings.MainWindowWidth = Width;
_viewModel.Data.Settings.MainWindowHeight = Height;
_viewModel.SaveAsync().GetAwaiter().GetResult();
_hotkeyService.Dispose();
_trayService?.Dispose();
e.Cancel = true;
await ShutdownAsync();
}
private void SearchTextBox_OnKeyDown(object sender, System.Windows.Input.KeyEventArgs e)
@@ -298,16 +315,11 @@ public partial class MainWindow : Window
RootGrid.LayoutTransform = new ScaleTransform(scale, scale);
}
private void RequestExit()
private async void RequestExit()
{
if (_viewModel.Data.Settings.ConfirmExit)
{
var confirmed = MessageBox.Show(
this,
"确定退出个人工具箱吗?退出后托盘和全局快捷键都会停止。",
"退出",
MessageBoxButton.YesNo,
MessageBoxImage.Question) == MessageBoxResult.Yes;
var confirmed = ShowExitConfirmation() == MessageBoxResult.Yes;
if (!confirmed)
{
@@ -315,9 +327,47 @@ public partial class MainWindow : Window
}
}
await ShutdownAsync();
}
private MessageBoxResult ShowExitConfirmation()
{
const string message = "确定退出个人工具箱吗?退出后托盘和全局快捷键都会停止。";
if (IsVisible)
{
return MessageBox.Show(this, message, "退出", MessageBoxButton.YesNo, MessageBoxImage.Question);
}
return MessageBox.Show(message, "退出", MessageBoxButton.YesNo, MessageBoxImage.Question);
}
private async Task ShutdownAsync()
{
if (_isShuttingDown)
{
return;
}
_isShuttingDown = true;
_exitRequested = true;
Close();
System.Windows.Application.Current.Shutdown();
_viewModel.Data.Settings.MainWindowWidth = Width;
_viewModel.Data.Settings.MainWindowHeight = Height;
try
{
await _viewModel.SaveAsync();
}
catch (Exception ex)
{
_viewModel.AddLog(LogLevel.Error, $"退出前保存配置失败:{ex.Message}");
}
finally
{
_hotkeyService.Dispose();
_trayService?.Dispose();
_cleanupCompleted = true;
System.Windows.Application.Current.Shutdown();
}
}
private static T? FindParent<T>(DependencyObject child)

View File

@@ -14,6 +14,7 @@ public static class AppearanceService
SetBrush(resources, "AppBackgroundBrush", theme == "Dark" ? "#151922" : "#F7F8FA");
SetBrush(resources, "PanelBackgroundBrush", theme == "Dark" ? "#1F2530" : "#FFFFFF");
SetBrush(resources, "CardBackgroundBrush", theme == "Dark" ? "#252C38" : "#FBFCFE");
SetBrush(resources, "SelectedCardBackgroundBrush", theme == "Dark" ? "#243B5E" : "#EFF5FF");
SetBrush(resources, "BadgeBackgroundBrush", theme == "Dark" ? "#303847" : "#EDF2F7");
SetBrush(resources, "IconBackgroundBrush", theme == "Dark" ? "#263D63" : "#E8F0FF");
SetBrush(resources, "BorderBrushSoft", theme == "Dark" ? "#3B4658" : "#D9DEE7");
@@ -58,6 +59,13 @@ public static class AppearanceService
private static void SetBrush(ResourceDictionary resources, string key, string color)
{
resources[key] = new SolidColorBrush((System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(color));
var parsed = (System.Windows.Media.Color)System.Windows.Media.ColorConverter.ConvertFromString(color);
if (resources[key] is SolidColorBrush existingBrush && !existingBrush.IsFrozen)
{
existingBrush.Color = parsed;
return;
}
resources[key] = new SolidColorBrush(parsed);
}
}

View File

@@ -84,11 +84,11 @@ public sealed class IconService
return type switch
{
ToolType.System => "SYS",
ToolType.Local => "APP",
ToolType.Url => "URL",
ToolType.Combination => "COM",
_ => "BOX"
ToolType.System => "\uE770",
ToolType.Local => "\uE8A5",
ToolType.Url => "\uE71B",
ToolType.Combination => "\uE8FD",
_ => "\uE90F"
};
}
@@ -191,41 +191,41 @@ public static class IconCatalog
{
private static readonly IReadOnlyList<IconDefinition> Definitions =
[
new("toolbox", "工具箱", "通用", "BOX"),
new("category", "分类", "通用", "TAG"),
new("system", "系统", "系统", "SYS"),
new("settings", "设置", "系统", "SET"),
new("notepad", "记事本", "系统", "TXT"),
new("calculator", "计算器", "系统", "123"),
new("taskmgr", "任务管理器", "系统", "CPU"),
new("control", "控制面板", "系统", "CTL"),
new("device", "设备管理器", "系统", "DEV"),
new("disk", "磁盘", "系统", "DSK"),
new("service", "服务", "系统", "SVC"),
new("registry", "注册表", "系统", "REG"),
new("network", "网络", "系统", "NET"),
new("apps", "应用列表", "系统", "APP"),
new("local", "本地工具", "文件", "APP"),
new("file", "文件", "文件", "FIL"),
new("folder", "文件夹", "文件", "DIR"),
new("document", "文档", "文件", "DOC"),
new("image", "图片", "文件", "IMG"),
new("video", "视频", "文件", "VID"),
new("audio", "音频", "文件", "AUD"),
new("archive", "压缩包", "文件", "ZIP"),
new("code", "代码", "文件", "COD"),
new("script", "脚本", "操作", "CMD"),
new("link", "网址", "操作", "URL"),
new("combination", "组合", "工作区", "COM"),
new("work", "工作", "工作区", "WRK"),
new("study", "学习", "工作区", "STD"),
new("edit", "剪辑", "工作区", "CUT"),
new("design", "设计", "工作区", "DSN"),
new("dev", "开发", "工作区", "DEV"),
new("ai", "AI", "工作区", "AI"),
new("star", "星标", "通用", "STR"),
new("flash", "闪电", "通用", "PWR"),
new("grid", "网格", "通用", "GRD")
new("toolbox", "工具箱", "通用", "\uE90F"),
new("category", "分类", "通用", "\uE71D"),
new("system", "系统", "系统", "\uE770"),
new("settings", "设置", "系统", "\uE713"),
new("notepad", "记事本", "系统", "\uE8A5"),
new("calculator", "计算器", "系统", "\uE8EF"),
new("taskmgr", "任务管理器", "系统", "\uE9D9"),
new("control", "控制面板", "系统", "\uE713"),
new("device", "设备管理器", "系统", "\uE772"),
new("disk", "磁盘", "系统", "\uEDA2"),
new("service", "服务", "系统", "\uE9F5"),
new("registry", "注册表", "系统", "\uE8A5"),
new("network", "网络", "系统", "\uE774"),
new("apps", "应用列表", "系统", "\uE71D"),
new("local", "本地工具", "文件", "\uE8A5"),
new("file", "文件", "文件", "\uE8A5"),
new("folder", "文件夹", "文件", "\uE8B7"),
new("document", "文档", "文件", "\uE8A5"),
new("image", "图片", "文件", "\uE91B"),
new("video", "视频", "文件", "\uE714"),
new("audio", "音频", "文件", "\uE8D6"),
new("archive", "压缩包", "文件", "\uE8B7"),
new("code", "代码", "文件", "\uE943"),
new("script", "脚本", "操作", "\uE756"),
new("link", "网址", "操作", "\uE71B"),
new("combination", "组合", "工作区", "\uE8FD"),
new("work", "工作", "工作区", "\uE821"),
new("study", "学习", "工作区", "\uE82D"),
new("edit", "剪辑", "工作区", "\uE70F"),
new("design", "设计", "工作区", "\uEC87"),
new("dev", "开发", "工作区", "\uE943"),
new("ai", "AI", "工作区", "\uE950"),
new("star", "星标", "通用", "\uE734"),
new("flash", "闪电", "通用", "\uE945"),
new("grid", "网格", "通用", "\uE80A")
];
public static IReadOnlyList<IconDefinition> All => Definitions;

View File

@@ -33,16 +33,16 @@ public sealed class ToolCardViewModel : ObservableObject
public bool ShowDescription => _settings.ShowToolDescriptions;
public double CardWidth => _settings.CardSize switch
{
"Small" => 178,
"Large" => 248,
_ => 210
"Small" => 220,
"Large" => 320,
_ => 260
};
public double CardHeight => _settings.CardSize switch
{
"Small" => 126,
"Large" => 172,
_ => 146
"Small" => 132,
"Large" => 178,
_ => 154
};
public string TypeLabel => Tool.Type switch

View File

@@ -6,8 +6,11 @@
Height="420"
MinWidth="320"
MinHeight="360"
Background="{DynamicResource AppBackgroundBrush}"
Foreground="{DynamicResource PrimaryTextBrush}"
WindowStartupLocation="CenterOwner">
<Grid Margin="16">
<Grid Margin="16"
Background="{DynamicResource AppBackgroundBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />

View File

@@ -1,4 +1,4 @@
<Window x:Class="PersonalToolbox.Views.CombinationEditorWindow"
<Window x:Class="PersonalToolbox.Views.CombinationEditorWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="编辑组合"
@@ -6,8 +6,11 @@
Height="640"
MinWidth="680"
MinHeight="560"
Background="{DynamicResource AppBackgroundBrush}"
Foreground="{DynamicResource PrimaryTextBrush}"
WindowStartupLocation="CenterOwner">
<Grid Margin="18">
<Grid Margin="18"
Background="{DynamicResource AppBackgroundBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
@@ -107,17 +110,18 @@
<Border Width="42"
Height="30"
CornerRadius="6"
Background="{StaticResource IconBackgroundBrush}">
Background="{DynamicResource IconBackgroundBrush}">
<TextBlock x:Name="IconPreviewTextBlock"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="SemiBold"
Foreground="{StaticResource PrimaryBrush}" />
FontFamily="Segoe MDL2 Assets"
FontSize="18"
Foreground="{DynamicResource PrimaryBrush}" />
</Border>
<TextBlock x:Name="IconNameTextBlock"
Margin="10,0,0,0"
VerticalAlignment="Center"
Foreground="{StaticResource SecondaryTextBrush}" />
Foreground="{DynamicResource SecondaryTextBrush}" />
<Button Content="选择图标"
Width="88"
Margin="12,0,0,0"

View File

@@ -1,4 +1,4 @@
<Window x:Class="PersonalToolbox.Views.HotkeyCaptureWindow"
<Window x:Class="PersonalToolbox.Views.HotkeyCaptureWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="录入快捷键"
@@ -6,34 +6,37 @@
Height="220"
MinWidth="380"
MinHeight="200"
Background="{DynamicResource AppBackgroundBrush}"
Foreground="{DynamicResource PrimaryTextBrush}"
WindowStartupLocation="CenterOwner"
PreviewKeyDown="Window_OnPreviewKeyDown">
<Grid Margin="18">
<Grid Margin="18"
Background="{DynamicResource AppBackgroundBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border BorderBrush="{StaticResource BorderBrushSoft}"
<Border BorderBrush="{DynamicResource BorderBrushSoft}"
BorderThickness="1"
CornerRadius="8"
Padding="18"
Background="{StaticResource PanelBackgroundBrush}">
Background="{DynamicResource PanelBackgroundBrush}">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="请按下要使用的快捷键"
FontSize="16"
FontWeight="SemiBold"
Foreground="{StaticResource PrimaryTextBrush}" />
Foreground="{DynamicResource PrimaryTextBrush}" />
<TextBlock Text="需要至少包含 Ctrl、Alt、Shift 或 Win 中的一个修饰键。"
Margin="0,8,0,0"
TextWrapping="Wrap"
Foreground="{StaticResource SecondaryTextBrush}" />
Foreground="{DynamicResource SecondaryTextBrush}" />
<TextBlock x:Name="CapturedTextBlock"
Text="等待输入..."
Margin="0,18,0,0"
FontSize="22"
FontWeight="SemiBold"
Foreground="{StaticResource PrimaryBrush}"
Foreground="{DynamicResource PrimaryBrush}"
ToolTip="捕获到有效组合后会自动关闭窗口。" />
</StackPanel>
</Border>

View File

@@ -1,4 +1,4 @@
<Window x:Class="PersonalToolbox.Views.IconPickerWindow"
<Window x:Class="PersonalToolbox.Views.IconPickerWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="选择图标"
@@ -6,8 +6,11 @@
Height="520"
MinWidth="460"
MinHeight="440"
Background="{DynamicResource AppBackgroundBrush}"
Foreground="{DynamicResource PrimaryTextBrush}"
WindowStartupLocation="CenterOwner">
<Grid Margin="16">
<Grid Margin="16"
Background="{DynamicResource AppBackgroundBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
@@ -42,21 +45,22 @@
<Border Width="42"
Height="30"
CornerRadius="6"
Background="{StaticResource IconBackgroundBrush}">
Background="{DynamicResource IconBackgroundBrush}">
<TextBlock Text="{Binding Text}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="SemiBold"
Foreground="{StaticResource PrimaryBrush}" />
FontFamily="Segoe MDL2 Assets"
FontSize="18"
Foreground="{DynamicResource PrimaryBrush}" />
</Border>
<TextBlock Grid.Column="1"
Text="{Binding Name}"
VerticalAlignment="Center"
Foreground="{StaticResource PrimaryTextBrush}" />
Foreground="{DynamicResource PrimaryTextBrush}" />
<TextBlock Grid.Column="2"
Text="{Binding Group}"
VerticalAlignment="Center"
Foreground="{StaticResource SecondaryTextBrush}" />
Foreground="{DynamicResource SecondaryTextBrush}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>

View File

@@ -5,8 +5,11 @@
Width="380"
Height="180"
ResizeMode="NoResize"
Background="{DynamicResource AppBackgroundBrush}"
Foreground="{DynamicResource PrimaryTextBrush}"
WindowStartupLocation="CenterOwner">
<Grid Margin="18">
<Grid Margin="18"
Background="{DynamicResource AppBackgroundBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />

View File

@@ -1,4 +1,4 @@
<Window x:Class="PersonalToolbox.Views.SettingsWindow"
<Window x:Class="PersonalToolbox.Views.SettingsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="设置"
@@ -6,8 +6,11 @@
Height="620"
MinWidth="740"
MinHeight="540"
Background="{DynamicResource AppBackgroundBrush}"
Foreground="{DynamicResource PrimaryTextBrush}"
WindowStartupLocation="CenterOwner">
<Grid Margin="18">
<Grid Margin="18"
Background="{DynamicResource AppBackgroundBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
@@ -102,7 +105,7 @@
Width="54"
Margin="12,0,0,0"
VerticalAlignment="Center"
Foreground="{StaticResource SecondaryTextBrush}" />
Foreground="{DynamicResource SecondaryTextBrush}" />
</StackPanel>
<CheckBox x:Name="ShowDescriptionCheckBox"

View File

@@ -1,12 +1,15 @@
<Window x:Class="PersonalToolbox.Views.ToolEditorWindow"
<Window x:Class="PersonalToolbox.Views.ToolEditorWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="编辑工具"
Width="560"
Height="620"
MinWidth="520"
Background="{DynamicResource AppBackgroundBrush}"
Foreground="{DynamicResource PrimaryTextBrush}"
WindowStartupLocation="CenterOwner">
<Grid Margin="18">
<Grid Margin="18"
Background="{DynamicResource AppBackgroundBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
@@ -158,17 +161,18 @@
<Border Width="42"
Height="30"
CornerRadius="6"
Background="{StaticResource IconBackgroundBrush}">
Background="{DynamicResource IconBackgroundBrush}">
<TextBlock x:Name="IconPreviewTextBlock"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontWeight="SemiBold"
Foreground="{StaticResource PrimaryBrush}" />
FontFamily="Segoe MDL2 Assets"
FontSize="18"
Foreground="{DynamicResource PrimaryBrush}" />
</Border>
<TextBlock x:Name="IconNameTextBlock"
Margin="10,0,0,0"
VerticalAlignment="Center"
Foreground="{StaticResource SecondaryTextBrush}" />
Foreground="{DynamicResource SecondaryTextBrush}" />
<Button Content="选择图标"
Width="88"
Margin="12,0,0,0"