diff --git a/src/Ursa.Themes.Semi/Controls/MultiComboBox.axaml b/src/Ursa.Themes.Semi/Controls/MultiComboBox.axaml index 080cbfc..5df1f9b 100644 --- a/src/Ursa.Themes.Semi/Controls/MultiComboBox.axaml +++ b/src/Ursa.Themes.Semi/Controls/MultiComboBox.axaml @@ -1,32 +1,166 @@ - - - - + + + + + - + - + - - - - + + + + + + - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/Ursa/Controls/ComboBox/MultiComboBox.cs b/src/Ursa/Controls/ComboBox/MultiComboBox.cs index 29bee67..8b141f1 100644 --- a/src/Ursa/Controls/ComboBox/MultiComboBox.cs +++ b/src/Ursa/Controls/ComboBox/MultiComboBox.cs @@ -2,19 +2,17 @@ using System.Collections.ObjectModel; using System.Collections.Specialized; using Avalonia; +using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Controls.Metadata; using Avalonia.Controls.Primitives; using Avalonia.Controls.Templates; +using Irihi.Avalonia.Shared.Helpers; namespace Ursa.Controls; -[TemplatePart( PART_ListBox, typeof(ListBox))] public class MultiComboBox: SelectingItemsControl { - public const string PART_ListBox = "PART_ListBox"; - private ListBox? _listBox; - private static ITemplate _defaultPanel = new FuncTemplate(() => new VirtualizingStackPanel()); public static readonly StyledProperty IsDropDownOpenProperty = @@ -26,8 +24,17 @@ public class MultiComboBox: SelectingItemsControl set => SetValue(IsDropDownOpenProperty, value); } + public static readonly StyledProperty MaxDropdownHeightProperty = AvaloniaProperty.Register( + nameof(MaxDropdownHeight)); + + public double MaxDropdownHeight + { + get => GetValue(MaxDropdownHeightProperty); + set => SetValue(MaxDropdownHeightProperty, value); + } + public new static readonly StyledProperty SelectedItemsProperty = AvaloniaProperty.Register( - nameof(SelectedItems)); + nameof(SelectedItems), new AvaloniaList()); public new IList? SelectedItems { @@ -43,14 +50,46 @@ public class MultiComboBox: SelectingItemsControl protected override bool NeedsContainerOverride(object? item, int index, out object? recycleKey) { - return NeedsContainer(item, out recycleKey); + recycleKey = item; + return item is not MultiComboBoxItem; } protected override Control CreateContainerForItemOverride(object? item, int index, object? recycleKey) { return new MultiComboBoxItem(); } - + + private Dictionary _disposables = new Dictionary(); + + protected override void PrepareContainerForItemOverride(Control container, object? item, int index) + { + base.PrepareContainerForItemOverride(container, item, index); + if(_disposables.TryGetValue(index, out var d)) + { + d?.Dispose(); + _disposables.Remove(index); + } + if (container is MultiComboBoxItem comboBoxItem) + { + comboBoxItem.IsSelected = SelectedItems?.Contains(item) ?? false; + var disposable = MultiComboBoxItem.IsSelectedProperty.Changed.Subscribe(a => + { + if (a.Sender == comboBoxItem) + { + if (comboBoxItem.IsSelected) + { + SelectedItems?.Add(item); + } + else + { + SelectedItems?.Remove(item); + } + } + }); + _disposables[index] = disposable; + } + } + internal void ItemFocused(MultiComboBoxItem dropDownItem) { if (IsDropDownOpen && dropDownItem.IsFocused && dropDownItem.IsArrangeValid) @@ -58,22 +97,5 @@ public class MultiComboBox: SelectingItemsControl dropDownItem.BringIntoView(); } } - - protected override void OnApplyTemplate(TemplateAppliedEventArgs e) - { - base.OnApplyTemplate(e); - _listBox = e.NameScope.Find(PART_ListBox); - if (_listBox != null) - { - _listBox.SelectionChanged += ListBox_SelectionChanged; - } - } - - private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - if (sender == _listBox) - { - this.SelectedItems = _listBox.SelectedItems; - } - } + } \ No newline at end of file diff --git a/src/Ursa/Controls/ComboBox/MultiComboBoxItem.cs b/src/Ursa/Controls/ComboBox/MultiComboBoxItem.cs index 8eaf26a..51202b4 100644 --- a/src/Ursa/Controls/ComboBox/MultiComboBoxItem.cs +++ b/src/Ursa/Controls/ComboBox/MultiComboBoxItem.cs @@ -1,11 +1,28 @@ using Avalonia; using Avalonia.Controls; +using Avalonia.Controls.Mixins; +using Avalonia.Input; using Irihi.Avalonia.Shared.Helpers; namespace Ursa.Controls; -public class MultiComboBoxItem: ListBoxItem +public class MultiComboBoxItem: ContentControl { + public static readonly StyledProperty IsSelectedProperty = AvaloniaProperty.Register( + nameof(IsSelected)); + + public bool IsSelected + { + get => GetValue(IsSelectedProperty); + set => SetValue(IsSelectedProperty, value); + } + + static MultiComboBoxItem() + { + IsSelectedProperty.AffectsPseudoClass(":selected"); + PressedMixin.Attach(); + FocusableProperty.OverrideDefaultValue(true); + } public MultiComboBoxItem() { this.GetObservable(IsFocusedProperty).Subscribe(a=> { @@ -15,4 +32,18 @@ public class MultiComboBoxItem: ListBoxItem } }); } + + protected override void OnPointerPressed(PointerPressedEventArgs e) + { + base.OnPointerPressed(e); + if (e.Handled) + { + return; + } + if (e.GetCurrentPoint(this).Properties.IsLeftButtonPressed) + { + this.IsSelected = !this.IsSelected; + e.Handled = true; + } + } } \ No newline at end of file