using System.Collections; using AtomUI.Controls.Themes; using AtomUI.Data; using Avalonia; using Avalonia.Controls; using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Layout; namespace AtomUI.Controls; internal class SelectResultOptionsBox : TemplatedControl { #region 公共属性定义 public static readonly DirectProperty SelectedOptionsProperty = AvaloniaProperty.RegisterDirect( nameof(SelectedOptions), o => o.SelectedOptions, (o, v) => o.SelectedOptions = v); public static readonly StyledProperty ModeProperty = AvaloniaProperty.Register(nameof(Mode)); public static readonly StyledProperty IsSearchEnabledProperty = Select.IsSearchEnabledProperty.AddOwner(); public static readonly StyledProperty IsDropDownOpenProperty = AvaloniaProperty.Register(nameof(IsDropDownOpen)); public static readonly StyledProperty SizeTypeProperty = SizeTypeAwareControlProperty.SizeTypeProperty.AddOwner(); public static readonly StyledProperty MaxTagCountProperty = Select.MaxTagCountProperty.AddOwner(); public static readonly StyledProperty IsResponsiveMaxTagCountProperty = Select.IsResponsiveMaxTagCountProperty.AddOwner(); private IList? _selectedOptions; public IList? SelectedOptions { get => _selectedOptions; set => SetAndRaise(SelectedOptionsProperty, ref _selectedOptions, value); } public SelectMode Mode { get => GetValue(ModeProperty); set => SetValue(ModeProperty, value); } public bool IsSearchEnabled { get => GetValue(IsSearchEnabledProperty); set => SetValue(IsSearchEnabledProperty, value); } public bool IsDropDownOpen { get => GetValue(IsDropDownOpenProperty); set => SetValue(IsDropDownOpenProperty, value); } public SizeType SizeType { get => GetValue(SizeTypeProperty); set => SetValue(SizeTypeProperty, value); } public int? MaxTagCount { get => GetValue(MaxTagCountProperty); set => SetValue(MaxTagCountProperty, value); } public bool? IsResponsiveMaxTagCount { get => GetValue(IsResponsiveMaxTagCountProperty); set => SetValue(IsResponsiveMaxTagCountProperty, value); } #endregion #region 内部属性定义 public static readonly DirectProperty IsShowDefaultPanelProperty = AvaloniaProperty.RegisterDirect( nameof(IsShowDefaultPanel), o => o.IsShowDefaultPanel, (o, v) => o.IsShowDefaultPanel = v); private bool _isShowDefaultPanel; public bool IsShowDefaultPanel { get => _isShowDefaultPanel; set => SetAndRaise(IsShowDefaultPanelProperty, ref _isShowDefaultPanel, value); } #endregion private WrapPanel? _defaultPanel; private SelectMaxTagAwarePanel? _maxCountAwarePanel; private SelectSearchTextBox? _searchTextBox; private SelectRemainInfoTag? _collapsedInfoTag; private protected readonly Dictionary _tagsBindingDisposables = new(); protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); if (change.Property == SelectedOptionsProperty) { HandleSelectedOptionsChanged(); } else if (change.Property == IsSearchEnabledProperty || change.Property == ModeProperty) { ConfigureSearchTextControl(); } else if (change.Property == IsDropDownOpenProperty) { ConfigureSearchTextReadOnly(); } else if (change.Property == IsResponsiveMaxTagCountProperty || change.Property == MaxTagCountProperty) { if (IsResponsiveMaxTagCount == true) { SetCurrentValue(IsShowDefaultPanelProperty, false); } else { SetCurrentValue(IsShowDefaultPanelProperty, true); } } else if (change.Property == IsShowDefaultPanelProperty) { _defaultPanel?.Children.Clear(); _maxCountAwarePanel?.Children.Clear(); HandleSelectedOptionsChanged(); } } protected override void OnPointerPressed(PointerPressedEventArgs e) { base.OnPointerPressed(e); e.Handled = false; } protected override void OnPointerReleased(PointerReleasedEventArgs e) { base.OnPointerReleased(e); e.Handled = false; } protected override void OnApplyTemplate(TemplateAppliedEventArgs e) { base.OnApplyTemplate(e); _defaultPanel = e.NameScope.Find(SelectResultOptionsBoxThemeConstants.DefaultPanelPart); _maxCountAwarePanel = e.NameScope.Find(SelectResultOptionsBoxThemeConstants.MaxCountAwarePanelPart); _searchTextBox = new SelectSearchTextBox { HorizontalAlignment = HorizontalAlignment.Stretch }; _collapsedInfoTag = new SelectRemainInfoTag() { IsClosable = false }; BindUtils.RelayBind(this, SizeTypeProperty, _searchTextBox, SizeTypeProperty); if (IsSearchEnabled) { if (Mode == SelectMode.Multiple) { if (IsShowDefaultPanel) { _defaultPanel?.Children.Add(_searchTextBox); } } } ConfigureSearchTextControl(); HandleSelectedOptionsChanged(); } private void HandleSelectedOptionsChanged() { if (_isShowDefaultPanel) { if (_defaultPanel != null) { _searchTextBox?.Clear(); _defaultPanel.Children.Clear(); foreach (var entry in _tagsBindingDisposables) { entry.Value.Dispose(); } _tagsBindingDisposables.Clear(); if (_selectedOptions != null) { foreach (var item in _selectedOptions) { if (item is SelectOption option) { var tag = new SelectTag { TagText = option.Header, Option = option }; _tagsBindingDisposables.Add(tag, BindUtils.RelayBind(this, SizeTypeProperty, tag, SizeTypeProperty)); _defaultPanel.Children.Add(tag); } } } if (_searchTextBox != null) { _defaultPanel.Children.Add(_searchTextBox); _searchTextBox.Focus(); } } } else { if (_maxCountAwarePanel != null) { _searchTextBox?.Clear(); _maxCountAwarePanel.Children.Clear(); foreach (var entry in _tagsBindingDisposables) { entry.Value.Dispose(); } _tagsBindingDisposables.Clear(); if (_selectedOptions != null) { foreach (var item in _selectedOptions) { if (item is SelectOption option) { var tag = new SelectTag { TagText = option.Header, Option = option }; _tagsBindingDisposables.Add(tag, BindUtils.RelayBind(this, SizeTypeProperty, tag, SizeTypeProperty)); _maxCountAwarePanel.Children.Add(tag); } } } if (_collapsedInfoTag != null) { _maxCountAwarePanel.Children.Add(_collapsedInfoTag); } if (_searchTextBox != null) { _maxCountAwarePanel.Children.Add(_searchTextBox); _searchTextBox.Focus(); } } } } private void ConfigureSearchTextControl() { if (_searchTextBox != null) { if (Mode == SelectMode.Multiple) { _searchTextBox.IsVisible = IsSearchEnabled; } } } private void ConfigureSearchTextReadOnly() { if (_searchTextBox != null) { if (IsDropDownOpen) { _searchTextBox.IsReadOnly = false; } else { _searchTextBox.Clear(); _searchTextBox.IsReadOnly = true; } } } }