123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267 |
- using Avalonia;
- using Avalonia.Controls;
- using Avalonia.Controls.Metadata;
- using Avalonia.Controls.Primitives;
- using Avalonia.LogicalTree;
- using Avalonia.Media;
- using Avalonia.Metadata;
- using Avalonia.Threading;
- using CommunityToolkit.Mvvm.Input;
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- using System.Collections.Specialized;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows.Input;
- namespace InABox.Avalonia.Components;
- public partial class ButtonStrip : TemplatedControl
- {
- public static StyledProperty<IBrush?> SelectedBackgroundProperty = AvaloniaProperty.Register<ButtonStripItem, IBrush?>(
- nameof(SelectedBackground));
- public static StyledProperty<IBrush?> SelectedForegroundProperty = AvaloniaProperty.Register<ButtonStripItem, IBrush?>(
- nameof(SelectedForeground));
- public static StyledProperty<double> ItemSpacingProperty = AvaloniaProperty.Register<ButtonStripItem, double>(
- nameof(ItemSpacing));
- public static StyledProperty<ObservableCollection<ButtonStripItem>> ItemsProperty =
- AvaloniaProperty.Register<ButtonStripItem, ObservableCollection<ButtonStripItem>>(nameof(Items));
- public static StyledProperty<IEnumerable?> ItemsSourceProperty =
- AvaloniaProperty.Register<ButtonStripItem, IEnumerable?>(nameof(ItemsSource));
- public static StyledProperty<ICommand> SelectedCommandProperty = AvaloniaProperty.Register<ButtonStrip, ICommand>(nameof(SelectedCommand));
- public static StyledProperty<object?> SelectedItemProperty = AvaloniaProperty.Register<ButtonStrip, object?>(nameof(SelectedItem));
- public IBrush? SelectedBackground
- {
- get => GetValue(SelectedBackgroundProperty);
- set => SetValue(SelectedBackgroundProperty, value);
- }
- public IBrush? SelectedForeground
- {
- get => GetValue(SelectedForegroundProperty);
- set => SetValue(SelectedForegroundProperty, value);
- }
- public double ItemSpacing
- {
- get => GetValue(ItemSpacingProperty);
- set => SetValue(ItemSpacingProperty, value);
- }
- public ICommand SelectedCommand
- {
- get => GetValue(SelectedCommandProperty);
- set => SetValue(SelectedCommandProperty, value);
- }
- public IEnumerable? ItemsSource
- {
- get => GetValue(ItemsSourceProperty);
- set => SetValue(ItemsSourceProperty, value);
- }
- [Content]
- public ObservableCollection<ButtonStripItem> Items
- {
- get => GetValue(ItemsProperty);
- set => SetValue(ItemsProperty, value);
- }
- private ButtonStripItem? SelectedButton
- {
- get => Items.FirstOrDefault(x => x.Selected);
- set
- {
- foreach(var item in Items)
- {
- item.Selected = item == value;
- }
- SelectedItem = value?.Tag;
- }
- }
- public object? SelectedItem
- {
- get => GetValue(SelectedItemProperty);
- set => SetValue(SelectedItemProperty, value);
- }
- public event EventHandler? SelectionChanged;
- static ButtonStrip()
- {
- ItemsProperty.Changed.AddClassHandler<ButtonStrip>(Items_Changed);
- ItemsSourceProperty.Changed.AddClassHandler<ButtonStrip>(ItemsSource_Changed);
- }
- private static void ItemsSource_Changed(ButtonStrip strip, AvaloniaPropertyChangedEventArgs args)
- {
- if(strip.ItemsSource is INotifyCollectionChanged notify)
- {
- notify.CollectionChanged += (sender, e) => strip.RebuildItems();
- }
- strip.RebuildItems();
- }
- private void RebuildItems()
- {
- Items.Clear();
- if(ItemsSource is not null)
- {
- foreach(var item in ItemsSource)
- {
- if(item is ButtonStripItem btn)
- {
- Items.Add(btn);
- }
- else
- {
- Items.Add(new(item?.ToString() ?? "") { Tag = item });
- }
- }
- }
- }
- private static void Items_Changed(ButtonStrip strip, AvaloniaPropertyChangedEventArgs args)
- {
- strip.LogicalChildren.Clear();
- if (strip.Items is not null)
- {
- strip.SelectedButton = strip.Items.FirstOrDefault();
- strip.LogicalChildren.AddRange(strip.Items);
- foreach(var item in strip.Items)
- {
- item.Command = strip.ItemSelectedCommand;
- }
- }
- }
- public ButtonStrip()
- {
- Items = new();
- Items.CollectionChanged += Items_CollectionChanged;
- }
- private void Items_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
- {
- SelectedButton ??= Items.FirstOrDefault();
- switch (e.Action)
- {
- case NotifyCollectionChangedAction.Add:
- AddControlItemsToLogicalChildren(e.NewItems);
- break;
- case NotifyCollectionChangedAction.Remove:
- RemoveControlItemsFromLogicalChildren(e.OldItems);
- break;
- }
- foreach(var item in Items)
- {
- item.Command = ItemSelectedCommand;
- }
- }
- private void AddControlItemsToLogicalChildren(IEnumerable? items)
- {
- if (items is null) return;
- List<ILogical>? toAdd = null;
- foreach(var i in items)
- {
- if(i is Control control && !LogicalChildren.Contains(control))
- {
- toAdd ??= new();
- toAdd.Add(control);
- }
- }
- if(toAdd is not null)
- {
- LogicalChildren.AddRange(toAdd);
- }
- }
- private void RemoveControlItemsFromLogicalChildren(IEnumerable? items)
- {
- if (items is null) return;
- List<ILogical>? toRemove = null;
- foreach(var i in items)
- {
- if(i is Control control)
- {
- toRemove ??= new();
- toRemove.Add(control);
- }
- }
- if(toRemove is not null)
- {
- LogicalChildren.RemoveAll(toRemove);
- }
- }
- [RelayCommand]
- private void ItemSelected(ButtonStripItem item)
- {
- var children = this.GetLogicalChildren().ToArray();
- SelectedButton = item;
- SelectionChanged?.Invoke(this, new());
- SelectedCommand?.Execute(item.Tag);
- }
- public void AddRange(IEnumerable<string> items)
- {
- foreach(var item in items)
- {
- Items.Add(new(item));
- }
- }
- }
- [PseudoClasses(":selected")]
- public class ButtonStripItem : TemplatedControl
- {
- public static StyledProperty<string> TextProperty = AvaloniaProperty.Register<ButtonStripItem, string>(nameof(Text));
- public static StyledProperty<bool> SelectedProperty = AvaloniaProperty.Register<ButtonStripItem, bool>(nameof(Selected));
- public static StyledProperty<int> IndexProperty = AvaloniaProperty.Register<ButtonStripItem, int>(nameof(Index));
- public static StyledProperty<ICommand> CommandProperty = AvaloniaProperty.Register<ButtonStripItem, ICommand>(nameof(Command));
- public string Text
- {
- get => GetValue(TextProperty);
- set => SetValue(TextProperty, value);
- }
- public bool Selected
- {
- get => GetValue(SelectedProperty);
- set => SetValue(SelectedProperty, value);
- }
- public int Index
- {
- get => GetValue(IndexProperty);
- set => SetValue(IndexProperty, value);
- }
- public ICommand Command
- {
- get => GetValue(CommandProperty);
- set => SetValue(CommandProperty, value);
- }
- public ButtonStripItem()
- {
- }
- public ButtonStripItem(string text)
- {
- Text = text;
- }
- static ButtonStripItem()
- {
- SelectedProperty.Changed.AddClassHandler<ButtonStripItem>(Selected_Changed);
- }
- private static void Selected_Changed(ButtonStripItem item, AvaloniaPropertyChangedEventArgs args)
- {
- item.PseudoClasses.Set(":selected", item.Selected);
- }
- }
|