diff --git a/demo/Ursa.Demo/Pages/MultiComboBoxDemo.axaml b/demo/Ursa.Demo/Pages/MultiComboBoxDemo.axaml
new file mode 100644
index 0000000..5b604af
--- /dev/null
+++ b/demo/Ursa.Demo/Pages/MultiComboBoxDemo.axaml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
diff --git a/demo/Ursa.Demo/Pages/MultiComboBoxDemo.axaml.cs b/demo/Ursa.Demo/Pages/MultiComboBoxDemo.axaml.cs
new file mode 100644
index 0000000..2a51be5
--- /dev/null
+++ b/demo/Ursa.Demo/Pages/MultiComboBoxDemo.axaml.cs
@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace Ursa.Demo.Pages;
+
+public partial class MultiComboBoxDemo : UserControl
+{
+ public MultiComboBoxDemo()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs b/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs
index e55a00a..15af99e 100644
--- a/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs
+++ b/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs
@@ -43,6 +43,7 @@ public class MainViewViewModel : ViewModelBase
MenuKeys.MenuKeyKeyGestureInput => new KeyGestureInputDemoViewModel(),
MenuKeys.MenuKeyLoading => new LoadingDemoViewModel(),
MenuKeys.MenuKeyMessageBox => new MessageBoxDemoViewModel(),
+ MenuKeys.MenuKeyMultiComboBox => new MultiComboBoxDemoViewModel(),
MenuKeys.MenuKeyNavMenu => new NavMenuDemoViewModel(),
MenuKeys.MenuKeyNumberDisplayer => new NumberDisplayerDemoViewModel(),
MenuKeys.MenuKeyNumericUpDown => new NumericUpDownDemoViewModel(),
diff --git a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs
index 3ac4eac..5a345ef 100644
--- a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs
+++ b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs
@@ -30,6 +30,7 @@ public class MenuViewModel: ViewModelBase
new() { MenuHeader = "KeyGestureInput", Key = MenuKeys.MenuKeyKeyGestureInput },
new() { MenuHeader = "Loading", Key = MenuKeys.MenuKeyLoading },
new() { MenuHeader = "Message Box", Key = MenuKeys.MenuKeyMessageBox },
+ new() { MenuHeader = "MultiComboBox", Key = MenuKeys.MenuKeyMultiComboBox, Status = "New" },
new() { MenuHeader = "Nav Menu", Key = MenuKeys.MenuKeyNavMenu, Status = "Updated" },
// new() { MenuHeader = "Number Displayer", Key = MenuKeys.MenuKeyNumberDisplayer, Status = "New" },
new() { MenuHeader = "Numeric UpDown", Key = MenuKeys.MenuKeyNumericUpDown },
@@ -70,6 +71,7 @@ public static class MenuKeys
public const string MenuKeyKeyGestureInput = "KeyGestureInput";
public const string MenuKeyLoading = "Loading";
public const string MenuKeyMessageBox = "MessageBox";
+ public const string MenuKeyMultiComboBox = "MultiComboBox";
public const string MenuKeyNavMenu = "NavMenu";
public const string MenuKeyNumberDisplayer = "NumberDisplayer";
public const string MenuKeyNumericUpDown = "NumericUpDown";
diff --git a/demo/Ursa.Demo/ViewModels/MultiComboBoxDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/MultiComboBoxDemoViewModel.cs
new file mode 100644
index 0000000..277332d
--- /dev/null
+++ b/demo/Ursa.Demo/ViewModels/MultiComboBoxDemoViewModel.cs
@@ -0,0 +1,51 @@
+using System.Collections.ObjectModel;
+using CommunityToolkit.Mvvm.ComponentModel;
+
+namespace Ursa.Demo.ViewModels;
+
+public class MultiComboBoxDemoViewModel: ObservableObject
+{
+ public ObservableCollection Items { get; set; }
+
+ public MultiComboBoxDemoViewModel()
+ {
+ Items = new ObservableCollection()
+ {
+ "Item 1",
+ "Item 2",
+ "Item 3",
+ "Item 4",
+ "Item 5",
+ "Item 6",
+ "Item 7",
+ "Item 8",
+ "Illinois",
+ "Indiana",
+ "Iowa",
+ "Kansas",
+ "Kentucky",
+ "Louisiana",
+ "Maine",
+ "Maryland",
+ "Massachusetts",
+ "Michigan",
+ "Minnesota",
+ "Mississippi",
+ "Missouri",
+ "Montana",
+ "Nebraska",
+ "Nevada",
+ "New Hampshire",
+ "New Jersey",
+ "New Mexico",
+ "New York",
+ "North Carolina",
+ "North Dakota",
+ "Ohio",
+ "Oklahoma",
+ "Oregon",
+ "Pennsylvania",
+ "Rhode Island",
+ };
+ }
+}
\ No newline at end of file
diff --git a/src/Ursa.Themes.Semi/Controls/MultiComboBox.axaml b/src/Ursa.Themes.Semi/Controls/MultiComboBox.axaml
new file mode 100644
index 0000000..39e3338
--- /dev/null
+++ b/src/Ursa.Themes.Semi/Controls/MultiComboBox.axaml
@@ -0,0 +1,270 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Ursa.Themes.Semi/Controls/TagInput.axaml b/src/Ursa.Themes.Semi/Controls/TagInput.axaml
index 6829870..4e49cf0 100644
--- a/src/Ursa.Themes.Semi/Controls/TagInput.axaml
+++ b/src/Ursa.Themes.Semi/Controls/TagInput.axaml
@@ -42,10 +42,10 @@
-
-
diff --git a/src/Ursa.Themes.Semi/Controls/_index.axaml b/src/Ursa.Themes.Semi/Controls/_index.axaml
index a369754..9a138a9 100644
--- a/src/Ursa.Themes.Semi/Controls/_index.axaml
+++ b/src/Ursa.Themes.Semi/Controls/_index.axaml
@@ -20,6 +20,7 @@
+
diff --git a/src/Ursa/Controls/ComboBox/MultiComboBox.cs b/src/Ursa/Controls/ComboBox/MultiComboBox.cs
new file mode 100644
index 0000000..1ca8e7d
--- /dev/null
+++ b/src/Ursa/Controls/ComboBox/MultiComboBox.cs
@@ -0,0 +1,190 @@
+using System.Collections;
+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 Avalonia.Input;
+using Avalonia.Interactivity;
+using Avalonia.LogicalTree;
+using Irihi.Avalonia.Shared.Helpers;
+using Irihi.Avalonia.Shared.Contracts;
+
+namespace Ursa.Controls;
+
+[TemplatePart(PART_BackgroundBorder, typeof(Border))]
+[PseudoClasses(PC_DropDownOpen, PC_Empty)]
+public class MultiComboBox: SelectingItemsControl, IInnerContentControl
+{
+ public const string PART_BackgroundBorder = "PART_BackgroundBorder";
+ public const string PC_DropDownOpen = ":dropdownopen";
+ public const string PC_Empty = ":selection-empty";
+
+ private Border? _rootBorder;
+
+ private static ITemplate _defaultPanel = new FuncTemplate(() => new VirtualizingStackPanel());
+
+ public static readonly StyledProperty IsDropDownOpenProperty =
+ ComboBox.IsDropDownOpenProperty.AddOwner();
+
+ public bool IsDropDownOpen
+ {
+ get => GetValue(IsDropDownOpenProperty);
+ set => SetValue(IsDropDownOpenProperty, value);
+ }
+
+ public static readonly StyledProperty MaxDropdownHeightProperty = AvaloniaProperty.Register(
+ nameof(MaxDropdownHeight));
+
+ public double MaxDropdownHeight
+ {
+ get => GetValue(MaxDropdownHeightProperty);
+ set => SetValue(MaxDropdownHeightProperty, value);
+ }
+
+ public static readonly StyledProperty MaxSelectionBoxHeightProperty = AvaloniaProperty.Register(
+ nameof(MaxSelectionBoxHeight));
+
+ public double MaxSelectionBoxHeight
+ {
+ get => GetValue(MaxSelectionBoxHeightProperty);
+ set => SetValue(MaxSelectionBoxHeightProperty, value);
+ }
+
+ public new static readonly StyledProperty SelectedItemsProperty = AvaloniaProperty.Register(
+ nameof(SelectedItems), new AvaloniaList