Add keyboard navigation and focus styles to TreeComboBox and MultiComboBox (#808)
* Initial plan * Add keyboard navigation and focus styles to TreeComboBox Co-authored-by: rabbitism <14807942+rabbitism@users.noreply.github.com> * Fix keyboard handler - add parentheses for clarity and handle Tab key properly Co-authored-by: rabbitism <14807942+rabbitism@users.noreply.github.com> * Add keyboard navigation to MultiComboBox Co-authored-by: rabbitism <14807942+rabbitism@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: rabbitism <14807942+rabbitism@users.noreply.github.com>
This commit is contained in:
@@ -189,6 +189,14 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</Style>
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="^:focus">
|
||||||
|
<Setter Property="Background" Value="{DynamicResource ComboBoxSelectorFocusBackground}" />
|
||||||
|
<Setter Property="BorderBrush" Value="{DynamicResource ComboBoxSelectorFocusBorderBrush}" />
|
||||||
|
<Style Selector="^ /template/ PathIcon#DropDownGlyph">
|
||||||
|
<Setter Property="Foreground" Value="{DynamicResource ComboBoxIconFocusForeground}" />
|
||||||
|
</Style>
|
||||||
|
</Style>
|
||||||
|
|
||||||
<Style Selector="^:dropdownopen">
|
<Style Selector="^:dropdownopen">
|
||||||
<Setter Property="BorderBrush" Value="{DynamicResource ComboBoxSelectorPressedBorderBrush}" />
|
<Setter Property="BorderBrush" Value="{DynamicResource ComboBoxSelectorPressedBorderBrush}" />
|
||||||
</Style>
|
</Style>
|
||||||
|
|||||||
@@ -206,6 +206,39 @@ public class MultiComboBox : SelectingItemsControl, IInnerContentControl, IPopup
|
|||||||
SetCurrentValue(IsDropDownOpenProperty, !IsDropDownOpen);
|
SetCurrentValue(IsDropDownOpenProperty, !IsDropDownOpen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnKeyDown(KeyEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnKeyDown(e);
|
||||||
|
if (e.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// F4 or Alt+Down/Up toggles dropdown
|
||||||
|
if ((e.Key == Key.F4 && !e.KeyModifiers.HasFlag(KeyModifiers.Alt)) ||
|
||||||
|
((e.Key == Key.Down || e.Key == Key.Up) && e.KeyModifiers.HasFlag(KeyModifiers.Alt)))
|
||||||
|
{
|
||||||
|
SetCurrentValue(IsDropDownOpenProperty, !IsDropDownOpen);
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
// Escape closes dropdown
|
||||||
|
else if (IsDropDownOpen && e.Key == Key.Escape)
|
||||||
|
{
|
||||||
|
SetCurrentValue(IsDropDownOpenProperty, false);
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
// Enter or Space opens dropdown when closed
|
||||||
|
else if (!IsDropDownOpen && (e.Key == Key.Return || e.Key == Key.Space))
|
||||||
|
{
|
||||||
|
SetCurrentValue(IsDropDownOpenProperty, true);
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
// Tab closes dropdown
|
||||||
|
else if (IsDropDownOpen && e.Key == Key.Tab)
|
||||||
|
{
|
||||||
|
SetCurrentValue(IsDropDownOpenProperty, false);
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal void ItemFocused(MultiComboBoxItem dropDownItem)
|
internal void ItemFocused(MultiComboBoxItem dropDownItem)
|
||||||
{
|
{
|
||||||
if (IsDropDownOpen && dropDownItem.IsFocused && dropDownItem.IsArrangeValid) dropDownItem.BringIntoView();
|
if (IsDropDownOpen && dropDownItem.IsFocused && dropDownItem.IsArrangeValid) dropDownItem.BringIntoView();
|
||||||
|
|||||||
@@ -190,6 +190,39 @@ public class TreeComboBox: ItemsControl, IClearControl, IInnerContentControl, IP
|
|||||||
ContainerForItemPreparedOverride(container, item, index);
|
ContainerForItemPreparedOverride(container, item, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnKeyDown(KeyEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnKeyDown(e);
|
||||||
|
if (e.Handled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// F4 or Alt+Down/Up toggles dropdown
|
||||||
|
if ((e.Key == Key.F4 && !e.KeyModifiers.HasFlag(KeyModifiers.Alt)) ||
|
||||||
|
((e.Key == Key.Down || e.Key == Key.Up) && e.KeyModifiers.HasFlag(KeyModifiers.Alt)))
|
||||||
|
{
|
||||||
|
SetCurrentValue(IsDropDownOpenProperty, !IsDropDownOpen);
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
// Escape closes dropdown
|
||||||
|
else if (IsDropDownOpen && e.Key == Key.Escape)
|
||||||
|
{
|
||||||
|
SetCurrentValue(IsDropDownOpenProperty, false);
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
// Enter or Space opens dropdown when closed
|
||||||
|
else if (!IsDropDownOpen && (e.Key == Key.Return || e.Key == Key.Space))
|
||||||
|
{
|
||||||
|
SetCurrentValue(IsDropDownOpenProperty, true);
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
// Tab closes dropdown
|
||||||
|
else if (IsDropDownOpen && e.Key == Key.Tab)
|
||||||
|
{
|
||||||
|
SetCurrentValue(IsDropDownOpenProperty, false);
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
protected override void OnPointerReleased(PointerReleasedEventArgs e)
|
||||||
{
|
{
|
||||||
base.OnPointerReleased(e);
|
base.OnPointerReleased(e);
|
||||||
|
|||||||
@@ -0,0 +1,235 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Headless.XUnit;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using UrsaControls = Ursa.Controls;
|
||||||
|
|
||||||
|
namespace HeadlessTest.Ursa.Controls.MultiComboBoxTests;
|
||||||
|
|
||||||
|
public class MultiComboBoxKeyboardTests
|
||||||
|
{
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void MultiComboBox_Should_Toggle_Dropdown_With_F4_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.MultiComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
|
||||||
|
// Act - Press F4 to open
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.F4
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(comboBox.IsDropDownOpen);
|
||||||
|
|
||||||
|
// Act - Press F4 again to close
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.F4
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void MultiComboBox_Should_Toggle_Dropdown_With_AltDown_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.MultiComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
|
||||||
|
// Act - Press Alt+Down to open
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Down,
|
||||||
|
KeyModifiers = KeyModifiers.Alt
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void MultiComboBox_Should_Toggle_Dropdown_With_AltUp_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.MultiComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
|
||||||
|
// Act - Press Alt+Up to open
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Up,
|
||||||
|
KeyModifiers = KeyModifiers.Alt
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void MultiComboBox_Should_Close_Dropdown_With_Escape_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.MultiComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
comboBox.IsDropDownOpen = true;
|
||||||
|
|
||||||
|
// Act - Press Escape to close
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Escape
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void MultiComboBox_Should_Not_Close_Dropdown_With_Escape_When_Already_Closed()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.MultiComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
comboBox.IsDropDownOpen = false;
|
||||||
|
|
||||||
|
// Act - Press Escape when already closed
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Escape
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void MultiComboBox_Should_Open_Dropdown_With_Enter_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.MultiComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
|
||||||
|
// Act - Press Enter to open
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Return
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void MultiComboBox_Should_Open_Dropdown_With_Space_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.MultiComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
|
||||||
|
// Act - Press Space to open
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Space
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void MultiComboBox_Should_Close_Dropdown_With_Tab_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.MultiComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
comboBox.IsDropDownOpen = true;
|
||||||
|
|
||||||
|
// Act - Press Tab to close
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Tab
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void MultiComboBox_Should_Not_Toggle_With_F4_And_Alt()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.MultiComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
|
||||||
|
// Act - Press F4 with Alt modifier (should not toggle)
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.F4,
|
||||||
|
KeyModifiers = KeyModifiers.Alt
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert - Should remain closed
|
||||||
|
Assert.False(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void MultiComboBox_Should_Be_Focusable()
|
||||||
|
{
|
||||||
|
// Arrange & Act
|
||||||
|
var comboBox = new UrsaControls.MultiComboBox();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(comboBox.Focusable);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,235 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Headless.XUnit;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using UrsaControls = Ursa.Controls;
|
||||||
|
|
||||||
|
namespace HeadlessTest.Ursa.Controls.TreeComboBoxTests;
|
||||||
|
|
||||||
|
public class TreeComboBoxKeyboardTests
|
||||||
|
{
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void TreeComboBox_Should_Toggle_Dropdown_With_F4_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.TreeComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
|
||||||
|
// Act - Press F4 to open
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.F4
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(comboBox.IsDropDownOpen);
|
||||||
|
|
||||||
|
// Act - Press F4 again to close
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.F4
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void TreeComboBox_Should_Toggle_Dropdown_With_AltDown_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.TreeComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
|
||||||
|
// Act - Press Alt+Down to open
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Down,
|
||||||
|
KeyModifiers = KeyModifiers.Alt
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void TreeComboBox_Should_Toggle_Dropdown_With_AltUp_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.TreeComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
|
||||||
|
// Act - Press Alt+Up to open
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Up,
|
||||||
|
KeyModifiers = KeyModifiers.Alt
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void TreeComboBox_Should_Close_Dropdown_With_Escape_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.TreeComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
comboBox.IsDropDownOpen = true;
|
||||||
|
|
||||||
|
// Act - Press Escape to close
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Escape
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void TreeComboBox_Should_Not_Close_Dropdown_With_Escape_When_Already_Closed()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.TreeComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
comboBox.IsDropDownOpen = false;
|
||||||
|
|
||||||
|
// Act - Press Escape when already closed
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Escape
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void TreeComboBox_Should_Open_Dropdown_With_Enter_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.TreeComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
|
||||||
|
// Act - Press Enter to open
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Return
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void TreeComboBox_Should_Open_Dropdown_With_Space_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.TreeComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
|
||||||
|
// Act - Press Space to open
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Space
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void TreeComboBox_Should_Close_Dropdown_With_Tab_Key()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.TreeComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
comboBox.IsDropDownOpen = true;
|
||||||
|
|
||||||
|
// Act - Press Tab to close
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.Tab
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.False(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void TreeComboBox_Should_Not_Toggle_With_F4_And_Alt()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var window = new Window();
|
||||||
|
var comboBox = new UrsaControls.TreeComboBox();
|
||||||
|
window.Content = comboBox;
|
||||||
|
window.Show();
|
||||||
|
comboBox.Focus();
|
||||||
|
|
||||||
|
// Act - Press F4 with Alt modifier (should not toggle)
|
||||||
|
comboBox.RaiseEvent(new KeyEventArgs
|
||||||
|
{
|
||||||
|
RoutedEvent = InputElement.KeyDownEvent,
|
||||||
|
Key = Key.F4,
|
||||||
|
KeyModifiers = KeyModifiers.Alt
|
||||||
|
});
|
||||||
|
Dispatcher.UIThread.RunJobs();
|
||||||
|
|
||||||
|
// Assert - Should remain closed
|
||||||
|
Assert.False(comboBox.IsDropDownOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
[AvaloniaFact]
|
||||||
|
public void TreeComboBox_Should_Be_Focusable()
|
||||||
|
{
|
||||||
|
// Arrange & Act
|
||||||
|
var comboBox = new UrsaControls.TreeComboBox();
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.True(comboBox.Focusable);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user