Files
v2rayN/v2rayN/v2rayN/Views/ProfilesView.xaml
T
2dust 2ebd2b28a8 Support Backspace for remove actions in UI lists
Changed key handling and menu input gestures to allow Backspace (in addition to Delete) for removing items in server, profile, and routing rule lists. This improves usability and consistency across both Avalonia and WPF views.
2025-11-18 16:54:42 +08:00

380 lines
21 KiB
XML

<reactiveui:ReactiveUserControl
x:Class="v2rayN.Views.ProfilesView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:base="clr-namespace:v2rayN.Base"
xmlns:conv="clr-namespace:v2rayN.Converters"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:reactiveui="http://reactiveui.net"
xmlns:resx="clr-namespace:ServiceLib.Resx;assembly=ServiceLib"
xmlns:vms="clr-namespace:ServiceLib.ViewModels;assembly=ServiceLib"
d:DesignHeight="450"
d:DesignWidth="800"
x:TypeArguments="vms:ProfilesViewModel"
Style="{StaticResource ViewGlobal}"
mc:Ignorable="d">
<UserControl.Resources>
<BooleanToVisibilityConverter x:Key="BoolToVisConverter" />
<conv:DelayColorConverter x:Key="DelayColorConverter" />
</UserControl.Resources>
<Grid>
<DockPanel>
<WrapPanel Margin="{StaticResource Margin4}" DockPanel.Dock="Top">
<ListBox
x:Name="lstGroup"
MaxHeight="200"
AutomationProperties.Name="{x:Static resx:ResUI.menuSubscription}"
FontSize="{DynamicResource StdFontSize}"
ItemContainerStyle="{StaticResource MyChipListBoxItem}"
Style="{StaticResource MaterialDesignChoiceChipPrimaryOutlineListBox}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Remarks}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button
x:Name="btnEditSub"
Width="30"
Height="30"
Margin="{StaticResource MarginLeftRight4}"
AutomationProperties.Name="{x:Static resx:ResUI.menuSubEdit}"
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
ToolTip="{x:Static resx:ResUI.menuSubEdit}">
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Edit" />
</Button>
<Button
x:Name="btnAddSub"
Width="30"
Height="30"
Margin="{StaticResource MarginLeftRight4}"
AutomationProperties.Name="{x:Static resx:ResUI.menuSubAdd}"
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
ToolTip="{x:Static resx:ResUI.menuSubAdd}">
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Plus" />
</Button>
<TextBox
x:Name="txtServerFilter"
Width="200"
Margin="{StaticResource MarginLeftRight4}"
VerticalContentAlignment="Center"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.MsgServerTitle}"
materialDesign:TextFieldAssist.HasClearButton="True"
AutomationProperties.Name="{x:Static resx:ResUI.MsgServerTitle}"
Style="{StaticResource DefTextBox}" />
<Button
x:Name="btnAutofitColumnWidth"
Width="30"
Height="30"
Margin="{StaticResource MarginLeftRight4}"
AutomationProperties.Name="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}"
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
ToolTip="{x:Static resx:ResUI.menuProfileAutofitColumnWidth}">
<materialDesign:PackIcon VerticalAlignment="Center" Kind="ArrowSplitVertical" />
</Button>
<Button
x:Name="btnFastRealPing"
Width="30"
Height="30"
Margin="{StaticResource MarginLeftRight4}"
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
ToolTip="{x:Static resx:ResUI.menuFastRealPing}">
<materialDesign:PackIcon VerticalAlignment="Center" Kind="LightningBolt" />
</Button>
<Button
x:Name="menuMixedTestServer"
Width="30"
Height="30"
Margin="{StaticResource MarginLeftRight4}"
Style="{StaticResource MaterialDesignFloatingActionMiniLightButton}"
ToolTip="{x:Static resx:ResUI.menuMixedTestServer}">
<materialDesign:PackIcon VerticalAlignment="Center" Kind="Speedometer" />
</Button>
</WrapPanel>
<DataGrid
x:Name="lstProfiles"
materialDesign:DataGridAssist.CellPadding="2,2"
AutoGenerateColumns="False"
BorderThickness="1"
CanUserAddRows="False"
CanUserResizeRows="False"
CanUserSortColumns="False"
EnableRowVirtualization="True"
Focusable="True"
GridLinesVisibility="All"
HeadersVisibility="All"
IsReadOnly="True"
RowHeaderWidth="40"
Style="{StaticResource DefDataGrid}">
<DataGrid.InputBindings>
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+C" />
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Ctrl+V" />
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Delete" />
<KeyBinding Command="ApplicationCommands.NotACommand" Gesture="Enter" />
</DataGrid.InputBindings>
<DataGrid.ContextMenu>
<ContextMenu Style="{StaticResource DefContextMenu}">
<MenuItem
x:Name="menuSetDefaultServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSetDefaultServer}"
InputGestureText="Enter" />
<MenuItem
x:Name="menuEditServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuEditServer}"
InputGestureText="Ctrl+D" />
<MenuItem
x:Name="menuCopyServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuCopyServer}" />
<MenuItem
x:Name="menuRemoveServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRemoveServer}"
InputGestureText="Back" />
<MenuItem
x:Name="menuRemoveDuplicateServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRemoveDuplicateServer}" />
<MenuItem
x:Name="menuRemoveInvalidServerResult"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRemoveInvalidServerResult}" />
<Separator />
<MenuItem
x:Name="menuTcpingServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuTcpingServer}"
InputGestureText="Ctrl+O" />
<MenuItem
x:Name="menuRealPingServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuRealPingServer}"
InputGestureText="Ctrl+R" />
<MenuItem
x:Name="menuSpeedServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSpeedServer}"
InputGestureText="Ctrl+T" />
<MenuItem
x:Name="menuSortServerResult"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSortServerResult}" />
<Separator />
<MenuItem
x:Name="menuMoveToGroup"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveToGroup}">
<MenuItem Height="Auto">
<MenuItem.Header>
<DockPanel>
<ComboBox
x:Name="cmbMoveToGroup"
Width="200"
materialDesign:HintAssist.Hint="{x:Static resx:ResUI.menuSubscription}"
DisplayMemberPath="Remarks"
FontSize="{DynamicResource StdFontSize}"
Style="{StaticResource MaterialDesignFilledComboBox}" />
</DockPanel>
</MenuItem.Header>
</MenuItem>
</MenuItem>
<MenuItem Header="{x:Static resx:ResUI.menuMoveTo}">
<MenuItem
x:Name="menuMoveTop"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveTop}"
InputGestureText="T" />
<MenuItem
x:Name="menuMoveUp"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveUp}"
InputGestureText="U" />
<MenuItem
x:Name="menuMoveDown"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveDown}"
InputGestureText="D" />
<MenuItem
x:Name="menuMoveBottom"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuMoveBottom}"
InputGestureText="B" />
</MenuItem>
<MenuItem
x:Name="menuSelectAll"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuSelectAll}"
InputGestureText="Ctrl+A" />
<Separator />
<MenuItem
x:Name="menuShareServer"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuShareServer}"
InputGestureText="Ctrl+F" />
<MenuItem Header="{x:Static resx:ResUI.menuExportConfig}">
<MenuItem
x:Name="menuExport2ClientConfig"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuExport2ClientConfig}" />
<MenuItem
x:Name="menuExport2ClientConfigClipboard"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuExport2ClientConfigClipboard}" />
<Separator />
<MenuItem
x:Name="menuExport2ShareUrl"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuExport2ShareUrl}"
InputGestureText="Ctrl+C" />
<MenuItem
x:Name="menuExport2ShareUrlBase64"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuExport2ShareUrlBase64}" />
</MenuItem>
<Separator />
<MenuItem Header="{x:Static resx:ResUI.menuGenGroupMultipleServer}">
<MenuItem
x:Name="menuGenGroupMultipleServerXrayRandom"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayRandom}" />
<MenuItem
x:Name="menuGenGroupMultipleServerXrayRoundRobin"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayRoundRobin}" />
<MenuItem
x:Name="menuGenGroupMultipleServerXrayLeastPing"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayLeastPing}" />
<MenuItem
x:Name="menuGenGroupMultipleServerXrayLeastLoad"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuGenGroupMultipleServerXrayLeastLoad}" />
<Separator />
<MenuItem
x:Name="menuGenGroupMultipleServerSingBoxLeastPing"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuGenGroupMultipleServerSingBoxLeastPing}" />
<MenuItem
x:Name="menuGenGroupMultipleServerSingBoxFallback"
Height="{StaticResource MenuItemHeight}"
Header="{x:Static resx:ResUI.menuGenGroupMultipleServerSingBoxFallback}" />
</MenuItem>
</ContextMenu>
</DataGrid.ContextMenu>
<DataGrid.Resources>
<Style BasedOn="{StaticResource MaterialDesignDataGridRow}" TargetType="DataGridRow">
<EventSetter Event="MouseDoubleClick" Handler="LstProfiles_MouseDoubleClick" />
</Style>
<Style BasedOn="{StaticResource MaterialDesignDataGridColumnHeader}" TargetType="DataGridColumnHeader">
<EventSetter Event="Click" Handler="LstProfiles_ColumnHeader_Click" />
</Style>
<Style BasedOn="{StaticResource MaterialDesignDataGridCell}" TargetType="DataGridCell">
<Style.Triggers>
<DataTrigger Binding="{Binding IsActive}" Value="True">
<Setter Property="Background" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
<Setter Property="Foreground" Value="Black" />
<Setter Property="BorderBrush" Value="{DynamicResource MaterialDesign.Brush.Primary.Light}" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Resources>
<DataGrid.Columns>
<base:MyDGTextColumn
Width="80"
Binding="{Binding ConfigType}"
ExName="ConfigType"
Header="{x:Static resx:ResUI.LvServiceType}" />
<base:MyDGTextColumn
Width="150"
Binding="{Binding Remarks}"
ExName="Remarks"
Header="{x:Static resx:ResUI.LvRemarks}" />
<base:MyDGTextColumn
Width="120"
Binding="{Binding Address}"
ExName="Address"
Header="{x:Static resx:ResUI.LvAddress}" />
<base:MyDGTextColumn
Width="60"
Binding="{Binding Port}"
ExName="Port"
Header="{x:Static resx:ResUI.LvPort}" />
<base:MyDGTextColumn
Width="100"
Binding="{Binding Network}"
ExName="Network"
Header="{x:Static resx:ResUI.LvTransportProtocol}" />
<base:MyDGTextColumn
Width="100"
Binding="{Binding StreamSecurity}"
ExName="StreamSecurity"
Header="{x:Static resx:ResUI.LvTLS}" />
<base:MyDGTextColumn
Width="100"
Binding="{Binding SubRemarks}"
ExName="SubRemarks"
Header="{x:Static resx:ResUI.LvSubscription}" />
<base:MyDGTextColumn
Width="100"
Binding="{Binding DelayVal}"
ExName="DelayVal"
Header="{x:Static resx:ResUI.LvTestDelay}"
SortMemberPath="Delay">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Right" />
<Setter Property="Foreground" Value="{Binding Delay, Converter={StaticResource DelayColorConverter}}" />
</Style>
</DataGridTextColumn.ElementStyle>
</base:MyDGTextColumn>
<base:MyDGTextColumn
Width="100"
Binding="{Binding SpeedVal}"
ExName="SpeedVal"
Header="{x:Static resx:ResUI.LvTestSpeed}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
</DataGridTextColumn.ElementStyle>
</base:MyDGTextColumn>
<base:MyDGTextColumn
x:Name="colTodayUp"
Width="100"
Binding="{Binding TodayUp}"
ExName="TodayUp"
Header="{x:Static resx:ResUI.LvTodayUploadDataAmount}" />
<base:MyDGTextColumn
x:Name="colTodayDown"
Width="100"
Binding="{Binding TodayDown}"
ExName="TodayDown"
Header="{x:Static resx:ResUI.LvTodayDownloadDataAmount}" />
<base:MyDGTextColumn
x:Name="colTotalUp"
Width="100"
Binding="{Binding TotalUp}"
ExName="TotalUp"
Header="{x:Static resx:ResUI.LvTotalUploadDataAmount}" />
<base:MyDGTextColumn
x:Name="colTotalDown"
Width="100"
Binding="{Binding TotalDown}"
ExName="TotalDown"
Header="{x:Static resx:ResUI.LvTotalDownloadDataAmount}" />
</DataGrid.Columns>
</DataGrid>
</DockPanel>
</Grid>
</reactiveui:ReactiveUserControl>