JJServiceManager/Windows/ServicePickerWindow.cs

153 lines
6.0 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
namespace JJServiceManager
{
/// <summary>추가 선택 화면: Windows 서비스 전체 목록에서 관리할 서비스를 고름</summary>
public sealed class ServicePickerWindow : Window
{
private readonly HashSet<string> _registered;
private readonly DataGrid _grid;
private readonly TextBox _search;
private readonly CheckBox _onlySelected;
private readonly TextBlock _loading;
private readonly TextBlock _status;
private List<ServiceInfo> _all = new List<ServiceInfo>();
private ICollectionView _view;
/// <summary>선택완료 시 체크된 서비스 (순서: 이름순)</summary>
public List<ServiceInfo> Result { get; private set; }
public ServicePickerWindow(IEnumerable<string> registeredNames)
{
_registered = new HashSet<string>(registeredNames, StringComparer.OrdinalIgnoreCase);
Title = "추가 선택 화면 - 서비스 선택";
Width = 1100;
Height = 700;
MinWidth = 700;
MinHeight = 400;
FontFamily = new FontFamily("Malgun Gothic");
FontSize = 13;
Background = Brushes2.Make("#FAFAFA");
WindowStartupLocation = WindowStartupLocation.CenterOwner;
ShowInTaskbar = false;
AppIcon.Apply(this);
var root = XamlLoader.LoadElement("ServicePicker.xaml");
Content = root;
_grid = root.Find<DataGrid>("grid");
_search = root.Find<TextBox>("txtSearch");
_onlySelected = root.Find<CheckBox>("chkOnlySelected");
_loading = root.Find<TextBlock>("txtLoading");
_status = root.Find<TextBlock>("txtStatus");
root.Find<Button>("btnAll").Click += (s, e) => SetVisibleSelected(true);
root.Find<Button>("btnNone").Click += (s, e) => SetVisibleSelected(false);
root.Find<Button>("btnDone").Click += (s, e) => Done();
root.Find<Button>("btnCancel").Click += (s, e) => Close();
_search.TextChanged += (s, e) => _view?.Refresh();
_onlySelected.Checked += (s, e) => _view?.Refresh();
_onlySelected.Unchecked += (s, e) => _view?.Refresh();
// Space: 마우스로 선택한 줄들의 체크 토글
_grid.PreviewKeyDown += (s, e) =>
{
if (e.Key == Key.Space)
{
var sel = _grid.SelectedItems.Cast<ServiceInfo>().ToList();
if (sel.Count > 0)
{
bool v = !sel.All(x => x.IsSelected);
foreach (var x in sel) x.IsSelected = v;
e.Handled = true;
}
}
};
// 더블클릭: 체크 토글
_grid.MouseDoubleClick += (s, e) =>
{
// 줄 위에서만 (열 제목·스크롤바·체크박스 제외)
var src = e.OriginalSource as DependencyObject;
if (FindAncestor<CheckBox>(src) != null) return;
var row = FindAncestor<DataGridRow>(src);
if (row?.Item is ServiceInfo si) si.IsSelected = !si.IsSelected;
};
KeyDown += (s, e) => { if (e.Key == Key.Escape) Close(); };
Loaded += async (s, e) => await LoadAsync();
}
private static T FindAncestor<T>(DependencyObject d) where T : DependencyObject
{
while (d != null)
{
if (d is T t) return t;
d = d is Visual || d is System.Windows.Media.Media3D.Visual3D
? VisualTreeHelper.GetParent(d)
: LogicalTreeHelper.GetParent(d);
}
return null;
}
private async Task LoadAsync()
{
_loading.Visibility = Visibility.Visible;
var reg = _registered;
_all = await Task.Run(() => ServiceInfo.LoadAll(reg));
_view = CollectionViewSource.GetDefaultView(_all);
_view.Filter = Filter;
// 기본 정렬: 이름 오름차순
_view.SortDescriptions.Add(new SortDescription(nameof(ServiceInfo.DisplayName), ListSortDirection.Ascending));
_grid.ItemsSource = _view;
foreach (var col in _grid.Columns)
if ((string)col.Header == "이름") col.SortDirection = ListSortDirection.Ascending;
_loading.Visibility = Visibility.Collapsed;
if (_all.Count == 0) _status.Text = "서비스 목록을 불러오지 못했습니다.";
}
private bool Filter(object o)
{
var s = (ServiceInfo)o;
if (_onlySelected.IsChecked == true && !s.IsSelected) return false;
var q = _search.Text?.Trim();
if (string.IsNullOrEmpty(q)) return true;
return Contains(s.DisplayName, q) || Contains(s.Description, q) || Contains(s.ServiceName, q);
}
private static bool Contains(string text, string q)
=> !string.IsNullOrEmpty(text) && text.IndexOf(q, StringComparison.OrdinalIgnoreCase) >= 0;
private void SetVisibleSelected(bool value)
{
if (_view == null) return;
foreach (ServiceInfo s in _view) s.IsSelected = value;
}
private void Done()
{
// 목록을 못 불러온 상태에서 선택완료하면 기존 등록이 지워지지 않도록 그냥 닫음
if (_view == null || _all.Count == 0)
{
Close();
return;
}
Result = _all.Where(s => s.IsSelected)
.OrderBy(s => s.DisplayName, StringComparer.CurrentCultureIgnoreCase)
.ToList();
DialogResult = true;
}
}
}