diff --git a/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml b/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml
new file mode 100644
index 00000000..ada7a7ca
--- /dev/null
+++ b/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml.cs b/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml.cs
new file mode 100644
index 00000000..42d34124
--- /dev/null
+++ b/v2rayN/v2rayN.Desktop/Views/ProfilesSelectWindow.axaml.cs
@@ -0,0 +1,141 @@
+using System.Linq;
+using System.Reactive.Disposables;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.Markup.Xaml;
+using Avalonia.ReactiveUI;
+using ReactiveUI;
+using ServiceLib.Manager;
+using v2rayN.Desktop.Common;
+
+namespace v2rayN.Desktop.Views;
+
+public partial class ProfilesSelectWindow : ReactiveWindow
+{
+ private static Config _config;
+
+ public Task ProfileItem => GetFirstProfileItemAsync();
+
+ public ProfilesSelectWindow()
+ {
+ InitializeComponent();
+
+ _config = AppManager.Instance.Config;
+
+ btnAutofitColumnWidth.Click += BtnAutofitColumnWidth_Click;
+ txtServerFilter.KeyDown += TxtServerFilter_KeyDown;
+ lstProfiles.KeyDown += LstProfiles_KeyDown;
+ lstProfiles.SelectionChanged += LstProfiles_SelectionChanged;
+ lstProfiles.LoadingRow += LstProfiles_LoadingRow;
+ lstProfiles.Sorting += LstProfiles_Sorting;
+ lstProfiles.DoubleTapped += LstProfiles_DoubleTapped;
+
+ ViewModel = new ProfilesSelectViewModel(UpdateViewHandler);
+ DataContext = ViewModel;
+
+ this.WhenActivated(disposables =>
+ {
+ this.OneWayBind(ViewModel, vm => vm.ProfileItems, v => v.lstProfiles.ItemsSource).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.SelectedProfile, v => v.lstProfiles.SelectedItem).DisposeWith(disposables);
+
+ this.Bind(ViewModel, vm => vm.SelectedSub, v => v.lstGroup.SelectedItem).DisposeWith(disposables);
+ this.Bind(ViewModel, vm => vm.ServerFilter, v => v.txtServerFilter.Text).DisposeWith(disposables);
+ });
+
+ btnSave.Click += (s, e) => ViewModel?.SelectFinish();
+ btnCancel.Click += (s, e) => Close(false);
+ }
+
+ private async Task UpdateViewHandler(EViewAction action, object? obj)
+ {
+ switch (action)
+ {
+ case EViewAction.CloseWindow:
+ Close(true);
+ break;
+ }
+ return await Task.FromResult(true);
+ }
+
+ private void LstProfiles_SelectionChanged(object? sender, SelectionChangedEventArgs e)
+ {
+ if (ViewModel != null)
+ {
+ ViewModel.SelectedProfiles = lstProfiles.SelectedItems.Cast().ToList();
+ }
+ }
+
+ private void LstProfiles_LoadingRow(object? sender, DataGridRowEventArgs e)
+ {
+ e.Row.Header = $" {e.Row.Index + 1}";
+ }
+
+ private void LstProfiles_DoubleTapped(object? sender, TappedEventArgs e)
+ {
+ ViewModel?.SelectFinish();
+ }
+
+ private async void LstProfiles_Sorting(object? sender, DataGridColumnEventArgs e)
+ {
+ e.Handled = true;
+ if (ViewModel != null && e.Column?.Tag?.ToString() != null)
+ {
+ await ViewModel.SortServer(e.Column.Tag.ToString());
+ }
+ e.Handled = false;
+ }
+
+ private void LstProfiles_KeyDown(object? sender, KeyEventArgs e)
+ {
+ if (e.KeyModifiers is KeyModifiers.Control or KeyModifiers.Meta)
+ {
+ if (e.Key == Key.A)
+ {
+ lstProfiles.SelectAll();
+ }
+ }
+ else
+ {
+ if (e.Key is Key.Enter or Key.Return)
+ {
+ ViewModel?.SelectFinish();
+ }
+ }
+ }
+
+ private void BtnAutofitColumnWidth_Click(object? sender, RoutedEventArgs e)
+ {
+ AutofitColumnWidth();
+ }
+
+ private void AutofitColumnWidth()
+ {
+ try
+ {
+ foreach (var col in lstProfiles.Columns)
+ {
+ col.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
+ }
+ }
+ catch
+ {
+ }
+ }
+
+ private void TxtServerFilter_KeyDown(object? sender, KeyEventArgs e)
+ {
+ if (e.Key is Key.Enter or Key.Return)
+ {
+ ViewModel?.RefreshServers();
+ }
+ }
+
+ public async Task GetFirstProfileItemAsync()
+ {
+ var item = await ViewModel?.GetProfileItem();
+ return item;
+ }
+}
diff --git a/v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml b/v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml
index f310f260..872a11f8 100644
--- a/v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml
+++ b/v2rayN/v2rayN.Desktop/Views/RoutingRuleDetailsWindow.axaml
@@ -54,13 +54,22 @@
Width="300"
Margin="{StaticResource Margin4}"
Text="{Binding SelectedSource.OutboundTag, Mode=TwoWay}" />
-
+ VerticalAlignment="Center">
+
+
+
(this);
+ if (result == true)
+ {
+ var profile = await selectWindow.ProfileItem;
+ if (profile != null)
+ {
+ cmbOutboundTag.Text = profile.Remarks;
+ }
+ }
+ }
}
diff --git a/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml b/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml
index 21c52189..7ebca48f 100644
--- a/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml
+++ b/v2rayN/v2rayN.Desktop/Views/SubEditWindow.axaml
@@ -204,6 +204,12 @@
Margin="{StaticResource Margin4}"
VerticalAlignment="Center"
Watermark="{x:Static resx:ResUI.LvPrevProfileTip}" />
+
+
{
txtRemarks.Focus();
}
+
+ private async void BtnSelectPrevProfile_Click(object? sender, RoutedEventArgs e)
+ {
+ var selectWindow = new ProfilesSelectWindow();
+ var result = await selectWindow.ShowDialog(this);
+ if (result == true)
+ {
+ var profile = await selectWindow.ProfileItem;
+ if (profile != null)
+ {
+ txtPrevProfile.Text = profile.Remarks;
+ }
+ }
+ }
+
+ private async void BtnSelectNextProfile_Click(object? sender, RoutedEventArgs e)
+ {
+ var selectWindow = new ProfilesSelectWindow();
+ var result = await selectWindow.ShowDialog(this);
+ if (result == true)
+ {
+ var profile = await selectWindow.ProfileItem;
+ if (profile != null)
+ {
+ txtNextProfile.Text = profile.Remarks;
+ }
+ }
+ }
}