committed by
GitHub
8 changed files with 245 additions and 73 deletions
@ -0,0 +1,65 @@ |
|||
using System; |
|||
using System.Collections.ObjectModel; |
|||
using System.Linq; |
|||
using System.Reactive; |
|||
using Avalonia.Controls; |
|||
using ReactiveUI; |
|||
|
|||
namespace ControlCatalog.ViewModels |
|||
{ |
|||
public class ListBoxPageViewModel : ReactiveObject |
|||
{ |
|||
private int _counter; |
|||
private SelectionMode _selectionMode; |
|||
|
|||
public ListBoxPageViewModel() |
|||
{ |
|||
Items = new ObservableCollection<string>(Enumerable.Range(1, 10000).Select(i => GenerateItem())); |
|||
Selection = new SelectionModel(); |
|||
Selection.Select(1); |
|||
|
|||
AddItemCommand = ReactiveCommand.Create(() => Items.Add(GenerateItem())); |
|||
|
|||
RemoveItemCommand = ReactiveCommand.Create(() => |
|||
{ |
|||
while (Selection.SelectedItems.Count > 0) |
|||
{ |
|||
Items.Remove((string)Selection.SelectedItems.First()); |
|||
} |
|||
}); |
|||
|
|||
SelectRandomItemCommand = ReactiveCommand.Create(() => |
|||
{ |
|||
var random = new Random(); |
|||
|
|||
using (Selection.Update()) |
|||
{ |
|||
Selection.ClearSelection(); |
|||
Selection.Select(random.Next(Items.Count - 1)); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
public ObservableCollection<string> Items { get; } |
|||
|
|||
public SelectionModel Selection { get; } |
|||
|
|||
public ReactiveCommand<Unit, Unit> AddItemCommand { get; } |
|||
|
|||
public ReactiveCommand<Unit, Unit> RemoveItemCommand { get; } |
|||
|
|||
public ReactiveCommand<Unit, Unit> SelectRandomItemCommand { get; } |
|||
|
|||
public SelectionMode SelectionMode |
|||
{ |
|||
get => _selectionMode; |
|||
set |
|||
{ |
|||
Selection.ClearSelection(); |
|||
this.RaiseAndSetIfChanged(ref _selectionMode, value); |
|||
} |
|||
} |
|||
|
|||
private string GenerateItem() => $"Item {_counter++.ToString()}"; |
|||
} |
|||
} |
|||
@ -0,0 +1,126 @@ |
|||
using System.Linq; |
|||
using Avalonia.Controls.Presenters; |
|||
using Avalonia.Controls.Templates; |
|||
using Avalonia.Input; |
|||
using Avalonia.Styling; |
|||
using Avalonia.UnitTests; |
|||
using Avalonia.VisualTree; |
|||
using Xunit; |
|||
|
|||
namespace Avalonia.Controls.UnitTests |
|||
{ |
|||
public class ListBoxTests_Multiple |
|||
{ |
|||
[Fact] |
|||
public void Focusing_Item_With_Shift_And_Arrow_Key_Should_Add_To_Selection() |
|||
{ |
|||
var target = new ListBox |
|||
{ |
|||
Template = new FuncControlTemplate(CreateListBoxTemplate), |
|||
Items = new[] { "Foo", "Bar", "Baz " }, |
|||
SelectionMode = SelectionMode.Multiple |
|||
}; |
|||
|
|||
ApplyTemplate(target); |
|||
|
|||
target.SelectedItem = "Foo"; |
|||
|
|||
target.Presenter.Panel.Children[1].RaiseEvent(new GotFocusEventArgs |
|||
{ |
|||
RoutedEvent = InputElement.GotFocusEvent, |
|||
NavigationMethod = NavigationMethod.Directional, |
|||
KeyModifiers = KeyModifiers.Shift |
|||
}); |
|||
|
|||
Assert.Equal(new[] { "Foo", "Bar" }, target.SelectedItems); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Focusing_Item_With_Ctrl_And_Arrow_Key_Should_Add_To_Selection() |
|||
{ |
|||
var target = new ListBox |
|||
{ |
|||
Template = new FuncControlTemplate(CreateListBoxTemplate), |
|||
Items = new[] { "Foo", "Bar", "Baz " }, |
|||
SelectionMode = SelectionMode.Multiple |
|||
}; |
|||
|
|||
ApplyTemplate(target); |
|||
|
|||
target.SelectedItem = "Foo"; |
|||
|
|||
target.Presenter.Panel.Children[1].RaiseEvent(new GotFocusEventArgs |
|||
{ |
|||
RoutedEvent = InputElement.GotFocusEvent, |
|||
NavigationMethod = NavigationMethod.Directional, |
|||
KeyModifiers = KeyModifiers.Control |
|||
}); |
|||
|
|||
Assert.Equal(new[] { "Foo", "Bar" }, target.SelectedItems); |
|||
} |
|||
|
|||
[Fact] |
|||
public void Focusing_Selected_Item_With_Ctrl_And_Arrow_Key_Should_Remove_From_Selection() |
|||
{ |
|||
var target = new ListBox |
|||
{ |
|||
Template = new FuncControlTemplate(CreateListBoxTemplate), |
|||
Items = new[] { "Foo", "Bar", "Baz " }, |
|||
SelectionMode = SelectionMode.Multiple |
|||
}; |
|||
|
|||
ApplyTemplate(target); |
|||
|
|||
target.SelectedItems.Add("Foo"); |
|||
target.SelectedItems.Add("Bar"); |
|||
|
|||
target.Presenter.Panel.Children[0].RaiseEvent(new GotFocusEventArgs |
|||
{ |
|||
RoutedEvent = InputElement.GotFocusEvent, |
|||
NavigationMethod = NavigationMethod.Directional, |
|||
KeyModifiers = KeyModifiers.Control |
|||
}); |
|||
|
|||
Assert.Equal(new[] { "Bar" }, target.SelectedItems); |
|||
} |
|||
|
|||
private Control CreateListBoxTemplate(ITemplatedControl parent, INameScope scope) |
|||
{ |
|||
return new ScrollViewer |
|||
{ |
|||
Template = new FuncControlTemplate(CreateScrollViewerTemplate), |
|||
Content = new ItemsPresenter |
|||
{ |
|||
Name = "PART_ItemsPresenter", |
|||
[~ItemsPresenter.ItemsProperty] = parent.GetObservable(ItemsControl.ItemsProperty).ToBinding(), |
|||
}.RegisterInNameScope(scope) |
|||
}; |
|||
} |
|||
|
|||
private Control CreateScrollViewerTemplate(ITemplatedControl parent, INameScope scope) |
|||
{ |
|||
return new ScrollContentPresenter |
|||
{ |
|||
Name = "PART_ContentPresenter", |
|||
[~ContentPresenter.ContentProperty] = |
|||
parent.GetObservable(ContentControl.ContentProperty).ToBinding(), |
|||
}.RegisterInNameScope(scope); |
|||
} |
|||
|
|||
private void ApplyTemplate(ListBox target) |
|||
{ |
|||
// Apply the template to the ListBox itself.
|
|||
target.ApplyTemplate(); |
|||
|
|||
// Then to its inner ScrollViewer.
|
|||
var scrollViewer = (ScrollViewer)target.GetVisualChildren().Single(); |
|||
scrollViewer.ApplyTemplate(); |
|||
|
|||
// Then make the ScrollViewer create its child.
|
|||
((ContentPresenter)scrollViewer.Presenter).UpdateChild(); |
|||
|
|||
// Now the ItemsPresenter should be reigstered, so apply its template.
|
|||
target.Presenter.ApplyTemplate(); |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue