Files
personal-toolbox/PersonalToolBox/Views/MainWindow.xaml
home-PC f33c89d2c4 添加单实例限制、应用图标、移除托盘设置菜单、快捷键暂停/恢复功能
单实例限制:通过命名Mutex和窗口消息广播确保只能运行一个实例,再次启动时唤起已有窗口

应用图标:exe文件嵌入app.ico,托盘和窗口图标统一使用该图标文件

移除托盘右键菜单中与显示主界面重复的设置选项

快捷键暂停/恢复:托盘菜单和主界面侧边栏均添加切换按钮,通过MainViewModel.IsHotKeyEnabled双向同步
2026-05-10 14:10:52 +08:00

460 lines
26 KiB
XML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<Window x:Class="PersonalToolBox.Views.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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:PersonalToolBox.Views"
xmlns:vm="clr-namespace:PersonalToolBox.ViewModels"
xmlns:models="clr-namespace:PersonalToolBox.Models"
xmlns:fa="http://schemas.awesome.incremented/wpf/xaml/fontawesome.sharp"
mc:Ignorable="d"
Title="个人工具箱" Height="650" Width="960"
WindowStartupLocation="CenterScreen"
Background="{DynamicResource Theme.Background}">
<Window.Resources>
<!-- 值转换器(必须定义在 DataTemplate 之前,确保 StaticResource 能解析) -->
<local:BoolToOpacityConverter x:Key="BoolToOpacityConverter"/>
<local:FirstCharConverter x:Key="FirstCharConverter"/>
<local:StringToIconCharConverter x:Key="StringToIconCharConverter"/>
<!-- 工具卡片模板 -->
<DataTemplate x:Key="ToolCardTemplate" DataType="{x:Type models:ToolItem}">
<Border Width="140" Height="100"
Margin="6"
Background="{DynamicResource Theme.CardBackground}"
BorderBrush="{DynamicResource Theme.CardBorder}"
BorderThickness="1"
CornerRadius="8"
Opacity="{Binding IsValid, Converter={StaticResource BoolToOpacityConverter}}"
Cursor="Hand"
ToolTip="{Binding Name}"
Tag="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Window}}">
<Border.InputBindings>
<MouseBinding Gesture="LeftDoubleClick"
Command="{Binding DataContext.ExecuteToolCommand, RelativeSource={RelativeSource AncestorType=Window}}"
CommandParameter="{Binding}"/>
</Border.InputBindings>
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="运行"
Command="{Binding PlacementTarget.Tag.ExecuteToolCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding}"/>
<MenuItem Header="编辑工具"
Command="{Binding PlacementTarget.Tag.EditToolCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding}">
<MenuItem.Style>
<Style TargetType="MenuItem">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsGroup}" Value="True">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
<MenuItem Header="编辑组合"
Command="{Binding PlacementTarget.Tag.EditGroupCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding}">
<MenuItem.Style>
<Style TargetType="MenuItem">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsGroup}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</MenuItem.Style>
</MenuItem>
<Separator/>
<MenuItem Header="删除"
Command="{Binding PlacementTarget.Tag.DeleteToolCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding}"/>
</ContextMenu>
</Border.ContextMenu>
<Grid>
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<Grid HorizontalAlignment="Center" Margin="0,0,0,4">
<!-- FontAwesome 图标IconCode 有值时显示) -->
<fa:IconBlock Icon="{Binding IconCode, Converter={StaticResource StringToIconCharConverter}}"
FontSize="28"
Foreground="{DynamicResource Theme.Accent}"
HorizontalAlignment="Center">
<fa:IconBlock.Style>
<Style TargetType="fa:IconBlock">
<Setter Property="Visibility" Value="Visible"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IconCode}" Value="">
<Setter Property="Visibility" Value="Collapsed"/>
</DataTrigger>
</Style.Triggers>
</Style>
</fa:IconBlock.Style>
</fa:IconBlock>
<!-- 首字母回退IconCode 为空时显示) -->
<TextBlock FontSize="28"
Foreground="{DynamicResource Theme.Accent}"
HorizontalAlignment="Center">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Setter Property="Text" Value="{Binding Name, Converter={StaticResource FirstCharConverter}}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IconCode}" Value="">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
<TextBlock Text="{Binding Name}"
FontSize="12"
Foreground="{DynamicResource Theme.Foreground}"
HorizontalAlignment="Center"
TextTrimming="CharacterEllipsis"
MaxWidth="120"/>
</StackPanel>
<!-- 组合角标 -->
<fa:IconBlock Icon="Cubes" FontSize="11"
Foreground="{DynamicResource Theme.Accent}"
HorizontalAlignment="Right"
VerticalAlignment="Top"
Margin="0,4,6,0">
<fa:IconBlock.Style>
<Style TargetType="fa:IconBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsGroup}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</fa:IconBlock.Style>
</fa:IconBlock>
<!-- 自启动角标 -->
<fa:IconBlock Icon="Rocket" FontSize="10"
Foreground="{DynamicResource Theme.Accent}"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="6,4,0,0">
<fa:IconBlock.Style>
<Style TargetType="fa:IconBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding AutoRunOnStart}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</fa:IconBlock.Style>
</fa:IconBlock>
</Grid>
</Border>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="3"/>
<RowDefinition Height="120"/>
</Grid.RowDefinitions>
<!-- ──────────────── 内容区 ──────────────── -->
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- ─── 左侧边栏 ─── -->
<Border Grid.Column="0" Background="{DynamicResource Theme.SidebarBackground}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="42"/>
<RowDefinition Height="42"/>
<RowDefinition Height="45"/>
<RowDefinition Height="45"/>
</Grid.RowDefinitions>
<ListBox Grid.Row="0"
x:Name="CategoryListBox"
ItemsSource="{Binding Categories}"
SelectedItem="{Binding SelectedCategory}"
Background="Transparent"
BorderThickness="0"
Foreground="{DynamicResource Theme.Foreground}"
SelectionMode="Single">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="16,10"/>
<Setter Property="Tag" Value="{Binding DataContext, RelativeSource={RelativeSource AncestorType=Window}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<Border x:Name="Border"
Background="Transparent"
BorderBrush="Transparent"
BorderThickness="3,0,0,0"
Padding="{TemplateBinding Padding}"
Tag="{TemplateBinding Tag}">
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="编辑"
Command="{Binding PlacementTarget.Tag.EditCategoryCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding}"/>
<MenuItem Header="删除"
Command="{Binding PlacementTarget.Tag.DeleteCategoryCommand, RelativeSource={RelativeSource AncestorType=ContextMenu}}"
CommandParameter="{Binding}"/>
</ContextMenu>
</Border.ContextMenu>
<TextBlock Text="{Binding Name}"
Foreground="{DynamicResource Theme.Foreground}"
FontSize="14"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Border" Property="Background" Value="#20FFFFFF"/>
<Setter TargetName="Border" Property="BorderBrush" Value="{DynamicResource Theme.Accent}"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="Border" Property="Background" Value="#10FFFFFF"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<!-- 分类管理按钮 -->
<Button Grid.Row="1"
Command="{Binding AddCategoryCommand}"
Background="Transparent"
BorderThickness="1"
BorderBrush="{DynamicResource Theme.CardBorder}"
Foreground="{DynamicResource Theme.Foreground}"
FontSize="12"
Height="35" Margin="10,0,10,3"
Cursor="Hand">
<StackPanel Orientation="Horizontal">
<TextBlock Text="+" FontSize="16" Margin="0,0,8,0"
VerticalAlignment="Center"/>
<TextBlock Text="添加分类" VerticalAlignment="Center"/>
</StackPanel>
</Button>
<Button Grid.Row="2"
Command="{Binding ToggleAutoStartCommand}"
Background="Transparent"
BorderThickness="1"
BorderBrush="{DynamicResource Theme.CardBorder}"
Foreground="{DynamicResource Theme.Foreground}"
FontSize="12"
Height="35" Margin="10,0,10,3"
Cursor="Hand">
<Button.Resources>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="⊗ 开机自启: 关"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsAutoStart}" Value="True">
<Setter Property="Text" Value="✔ 开机自启: 开"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Resources>
<TextBlock VerticalAlignment="Center" TextAlignment="Center"/>
</Button>
<Button Grid.Row="3"
Command="{Binding ToggleThemeCommand}"
Background="Transparent"
BorderThickness="1"
BorderBrush="{DynamicResource Theme.CardBorder}"
Foreground="{DynamicResource Theme.Foreground}"
FontSize="12"
Height="35" Margin="10,0,10,3"
Cursor="Hand">
<StackPanel Orientation="Horizontal">
<TextBlock Text="◐" FontSize="16" Margin="0,0,8,0"
VerticalAlignment="Center"/>
<TextBlock Text="切换主题" VerticalAlignment="Center"/>
</StackPanel>
</Button>
<Button Grid.Row="4"
Command="{Binding ToggleHotKeyCommand}"
Background="Transparent"
BorderThickness="1"
BorderBrush="{DynamicResource Theme.CardBorder}"
Foreground="{DynamicResource Theme.Foreground}"
FontSize="12"
Height="35" Margin="10,0,10,10"
Cursor="Hand">
<Button.Resources>
<Style TargetType="TextBlock">
<Setter Property="Text" Value="⏸ 暂停快捷键"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsHotKeyEnabled}" Value="False">
<Setter Property="Text" Value="▶ 恢复快捷键"/>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Resources>
<TextBlock VerticalAlignment="Center" TextAlignment="Center"/>
</Button>
</Grid>
</Border>
<!-- ─── 右侧主体区 ─── -->
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="{DynamicResource Theme.Background}"
BorderBrush="{DynamicResource Theme.CardBorder}"
BorderThickness="0,0,0,1">
<Grid Margin="12,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0"
Text="{Binding SearchText, UpdateSourceTrigger=PropertyChanged}"
Background="{DynamicResource Theme.InputBackground}"
Foreground="{DynamicResource Theme.Foreground}"
BorderBrush="{DynamicResource Theme.InputBorder}"
BorderThickness="1"
FontSize="14"
VerticalContentAlignment="Center"
Height="32"
Margin="0,0,12,0"
Padding="8,0"/>
<Button Grid.Column="1"
Content="+ 添加工具"
Command="{Binding AddToolCommand}"
Background="{DynamicResource Theme.ButtonBackground}"
Foreground="{DynamicResource Theme.ButtonForeground}"
BorderThickness="0"
FontSize="12"
Height="32"
Cursor="Hand"
Margin="0,0,6,0">
<Button.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="4"/>
</Style>
</Button.Resources>
</Button>
<Button Grid.Column="2"
Content="+ 添加组合"
Command="{Binding AddGroupCommand}"
Background="{DynamicResource Theme.Accent}"
Foreground="{DynamicResource Theme.ButtonForeground}"
BorderThickness="0"
FontSize="12"
Height="32"
Cursor="Hand">
<Button.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="4"/>
</Style>
</Button.Resources>
</Button>
</Grid>
</Border>
<ScrollViewer Grid.Row="1"
VerticalScrollBarVisibility="Auto"
Background="{DynamicResource Theme.Background}">
<ItemsControl ItemsSource="{Binding FilteredTools}"
Margin="8">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<StaticResource ResourceKey="ToolCardTemplate"/>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Grid>
<!-- ──────────────── 分隔线 ──────────────── -->
<Border Grid.Row="1" Background="{DynamicResource Theme.CardBorder}"/>
<!-- ──────────────── 底部日志栏 ──────────────── -->
<Border Grid.Row="2" Background="{DynamicResource Theme.LogBackground}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0"
Background="{DynamicResource Theme.SidebarBackground}"
BorderBrush="{DynamicResource Theme.CardBorder}"
BorderThickness="0,0,0,1">
<Grid Margin="10,0">
<TextBlock Text="运行日志"
Foreground="{DynamicResource Theme.Foreground}"
FontSize="12" FontWeight="SemiBold"
VerticalAlignment="Center"/>
<Button Content="清空日志"
Command="{Binding ClearLogsCommand}"
Background="Transparent"
Foreground="{DynamicResource Theme.TextSecondary}"
BorderThickness="0"
FontSize="11"
HorizontalAlignment="Right"
Height="22"
Cursor="Hand"/>
</Grid>
</Border>
<ListBox Grid.Row="1"
x:Name="LogListBox"
ItemsSource="{Binding Logs}"
Background="Transparent"
BorderThickness="0"
Foreground="{DynamicResource Theme.Foreground}"
FontFamily="Consolas"
FontSize="12"
VirtualizingPanel.IsVirtualizing="True">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Padding" Value="0,1,0,0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate DataType="{x:Type models:LogEntry}">
<TextBlock Text="{Binding .}" Padding="8,1"
Foreground="{DynamicResource Theme.Foreground}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Border>
</Grid>
</Window>