using v2rayN.Desktop.Base; namespace v2rayN.Desktop.Views; public partial class AddGroupServerWindow : WindowBase { public AddGroupServerWindow() { InitializeComponent(); } public AddGroupServerWindow(ProfileItem profileItem) { InitializeComponent(); Loaded += Window_Loaded; btnCancel.Click += (s, e) => Close(); lstChild.SelectionChanged += LstChild_SelectionChanged; tabControl.SelectionChanged += TabControl_SelectionChanged; ViewModel = new AddGroupServerViewModel(profileItem, UpdateViewHandler); cmbCoreType.ItemsSource = Global.CoreTypes; cmbPolicyGroupType.ItemsSource = new List { ResUI.TbLeastPing, ResUI.TbFallback, ResUI.TbRandom, ResUI.TbRoundRobin, ResUI.TbLeastLoad, }; cmbFilter.ItemsSource = Global.PolicyGroupDefaultFilterList; switch (profileItem.ConfigType) { case EConfigType.PolicyGroup: Title = ResUI.TbConfigTypePolicyGroup; break; case EConfigType.ProxyChain: Title = ResUI.TbConfigTypeProxyChain; gridPolicyGroup.IsVisible = false; if (tabControl.Items.Count > 0) { tabControl.Items.RemoveAt(0); } break; } this.WhenActivated(disposables => { this.Bind(ViewModel, vm => vm.SelectedSource.Remarks, v => v.txtRemarks.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.CoreType, v => v.cmbCoreType.SelectedValue).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.PolicyGroupType, v => v.cmbPolicyGroupType.SelectedValue).DisposeWith(disposables); //this.OneWayBind(ViewModel, vm => vm.SubItems, v => v.cmbSubChildItems.ItemsSource).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedSubItem, v => v.cmbSubChildItems.SelectedItem).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.Filter, v => v.cmbFilter.Text).DisposeWith(disposables); this.Bind(ViewModel, vm => vm.SelectedChild, v => v.lstChild.SelectedItem).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.RemoveCmd, v => v.menuRemoveChildServer).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MoveTopCmd, v => v.menuMoveTop).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MoveUpCmd, v => v.menuMoveUp).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MoveDownCmd, v => v.menuMoveDown).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.MoveBottomCmd, v => v.menuMoveBottom).DisposeWith(disposables); this.BindCommand(ViewModel, vm => vm.SaveCmd, v => v.btnSave).DisposeWith(disposables); }); // Context menu actions that require custom logic (Add, SelectAll) menuAddChildServer.Click += MenuAddChild_Click; menuSelectAllChild.Click += (s, e) => lstChild.SelectAll(); // Keyboard shortcuts when focus is within grid AddHandler(KeyDownEvent, AddGroupServerWindow_KeyDown, RoutingStrategies.Tunnel); lstChild.LoadingRow += LstChild_LoadingRow; } private void LstChild_LoadingRow(object? sender, DataGridRowEventArgs e) { e.Row.Header = $" {e.Row.Index + 1}"; } private async Task UpdateViewHandler(EViewAction action, object? obj) { switch (action) { case EViewAction.CloseWindow: Close(true); break; } return await Task.FromResult(true); } private void Window_Loaded(object? sender, RoutedEventArgs e) { txtRemarks.Focus(); } private void AddGroupServerWindow_KeyDown(object? sender, KeyEventArgs e) { if (!lstChild.IsKeyboardFocusWithin) { return; } if ((e.KeyModifiers & (KeyModifiers.Control | KeyModifiers.Meta)) != 0) { if (e.Key == Key.A) { lstChild.SelectAll(); e.Handled = true; } } else { switch (e.Key) { case Key.T: ViewModel?.MoveServer(EMove.Top); e.Handled = true; break; case Key.U: ViewModel?.MoveServer(EMove.Up); e.Handled = true; break; case Key.D: ViewModel?.MoveServer(EMove.Down); e.Handled = true; break; case Key.B: ViewModel?.MoveServer(EMove.Bottom); e.Handled = true; break; case Key.Delete: case Key.Back: ViewModel?.ChildRemoveAsync(); e.Handled = true; break; } } } private async void MenuAddChild_Click(object? sender, RoutedEventArgs e) { var selectWindow = new ProfilesSelectWindow(); if (ViewModel?.SelectedSource?.ConfigType == EConfigType.PolicyGroup) { selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom }, exclude: true); } else { selectWindow.SetConfigTypeFilter(new[] { EConfigType.Custom, EConfigType.PolicyGroup, EConfigType.ProxyChain }, exclude: true); } selectWindow.AllowMultiSelect(true); var result = await selectWindow.ShowDialog(this); if (result == true) { var profiles = await selectWindow.ProfileItems; ViewModel?.ChildItemsObs.AddRange(profiles); } } private void LstChild_SelectionChanged(object? sender, SelectionChangedEventArgs e) { if (ViewModel != null) { ViewModel.SelectedChildren = lstChild.SelectedItems.Cast().ToList(); } } private async void TabControl_SelectionChanged(object? sender, SelectionChangedEventArgs e) { try { if (e.Source is not TabControl tc) { return; } if (!(tc.SelectedIndex == tc.Items.Count - 1 && tc.Items.Count > 0)) { return; } if (ViewModel == null) { return; } await ViewModel.UpdatePreviewList(); } catch { // ignored } } }