|
|
@@ -1,32 +1,89 @@
|
|
|
-using System.Collections.ObjectModel;
|
|
|
+#nullable enable
|
|
|
+using System.Collections;
|
|
|
+using System.Collections.ObjectModel;
|
|
|
+using System.Collections.Specialized;
|
|
|
using Moq;
|
|
|
+using Terminal.Gui;
|
|
|
+using UnitTests;
|
|
|
+using Xunit;
|
|
|
+using Xunit.Abstractions;
|
|
|
+
|
|
|
+// ReSharper disable AccessToModifiedClosure
|
|
|
|
|
|
namespace UnitTests_Parallelizable.ViewsTests;
|
|
|
|
|
|
-public class ListViewTests
|
|
|
+public class ListViewTests (ITestOutputHelper output)
|
|
|
{
|
|
|
+ private readonly ITestOutputHelper _output = output;
|
|
|
+ [Fact]
|
|
|
+ public void CollectionNavigatorMatcher_KeybindingsOverrideNavigator ()
|
|
|
+ {
|
|
|
+ ObservableCollection<string> source = ["apricot", "arm", "bat", "batman", "bates hotel", "candle"];
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
+
|
|
|
+ lv.SetFocus ();
|
|
|
+
|
|
|
+ lv.KeyBindings.Add (Key.B, Command.Down);
|
|
|
+
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+
|
|
|
+ // Keys should be consumed to move down the navigation i.e. to apricot
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.B));
|
|
|
+ Assert.Equal (0, lv.SelectedItem);
|
|
|
+
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.B));
|
|
|
+ Assert.Equal (1, lv.SelectedItem);
|
|
|
+
|
|
|
+ // There is no keybinding for Key.C so it hits collection navigator i.e. we jump to candle
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.C));
|
|
|
+ Assert.Equal (5, lv.SelectedItem);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void ListView_CollectionNavigatorMatcher_KeybindingsOverrideNavigator ()
|
|
|
+ {
|
|
|
+ ObservableCollection<string> source = ["apricot", "arm", "bat", "batman", "bates hotel", "candle"];
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
+
|
|
|
+ lv.SetFocus ();
|
|
|
+
|
|
|
+ lv.KeyBindings.Add (Key.B, Command.Down);
|
|
|
+
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+
|
|
|
+ // Keys should be consumed to move down the navigation i.e. to apricot
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.B));
|
|
|
+ Assert.Equal (0, lv.SelectedItem);
|
|
|
+
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.B));
|
|
|
+ Assert.Equal (1, lv.SelectedItem);
|
|
|
+
|
|
|
+ // There is no keybinding for Key.C so it hits collection navigator i.e. we jump to candle
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.C));
|
|
|
+ Assert.Equal (5, lv.SelectedItem);
|
|
|
+ }
|
|
|
+
|
|
|
[Fact]
|
|
|
public void ListViewCollectionNavigatorMatcher_DefaultBehaviour ()
|
|
|
{
|
|
|
- ObservableCollection<string> source = new () { "apricot", "arm", "bat", "batman", "bates hotel", "candle" };
|
|
|
- ListView lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
+ ObservableCollection<string> source = ["apricot", "arm", "bat", "batman", "bates hotel", "candle"];
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
|
|
|
// Keys are consumed during navigation
|
|
|
Assert.True (lv.NewKeyDownEvent (Key.B));
|
|
|
Assert.True (lv.NewKeyDownEvent (Key.A));
|
|
|
Assert.True (lv.NewKeyDownEvent (Key.T));
|
|
|
|
|
|
- Assert.Equal ("bat", (string)lv.Source.ToList () [lv.SelectedItem]);
|
|
|
+ Assert.Equal ("bat", (string)lv.Source.ToList () [lv.SelectedItem!.Value]!);
|
|
|
}
|
|
|
|
|
|
[Fact]
|
|
|
public void ListViewCollectionNavigatorMatcher_IgnoreKeys ()
|
|
|
{
|
|
|
- ObservableCollection<string> source = new () { "apricot", "arm", "bat", "batman", "bates hotel", "candle" };
|
|
|
- ListView lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
-
|
|
|
+ ObservableCollection<string> source = ["apricot", "arm", "bat", "batman", "bates hotel", "candle"];
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
|
|
|
- var matchNone = new Mock<ICollectionNavigatorMatcher> ();
|
|
|
+ Mock<ICollectionNavigatorMatcher> matchNone = new ();
|
|
|
|
|
|
matchNone.Setup (m => m.IsCompatibleKey (It.IsAny<Key> ()))
|
|
|
.Returns (false);
|
|
|
@@ -45,11 +102,10 @@ public class ListViewTests
|
|
|
[Fact]
|
|
|
public void ListViewCollectionNavigatorMatcher_OverrideMatching ()
|
|
|
{
|
|
|
- ObservableCollection<string> source = new () { "apricot", "arm", "bat", "batman", "bates hotel", "candle" };
|
|
|
- ListView lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
-
|
|
|
+ ObservableCollection<string> source = ["apricot", "arm", "bat", "batman", "bates hotel", "candle"];
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
|
|
|
- var matchNone = new Mock<ICollectionNavigatorMatcher> ();
|
|
|
+ Mock<ICollectionNavigatorMatcher> matchNone = new ();
|
|
|
|
|
|
matchNone.Setup (m => m.IsCompatibleKey (It.IsAny<Key> ()))
|
|
|
.Returns (true);
|
|
|
@@ -59,6 +115,7 @@ public class ListViewTests
|
|
|
.Returns ((string s, object key) => s.StartsWith ('B') && key?.ToString () == "candle");
|
|
|
|
|
|
lv.KeystrokeNavigator.Matcher = matchNone.Object;
|
|
|
+
|
|
|
// Keys are consumed during navigation
|
|
|
Assert.True (lv.NewKeyDownEvent (Key.B));
|
|
|
Assert.Equal (5, lv.SelectedItem);
|
|
|
@@ -67,54 +124,1461 @@ public class ListViewTests
|
|
|
Assert.True (lv.NewKeyDownEvent (Key.T));
|
|
|
Assert.Equal (5, lv.SelectedItem);
|
|
|
|
|
|
- Assert.Equal ("candle", (string)lv.Source.ToList () [lv.SelectedItem]);
|
|
|
+ Assert.Equal ("candle", (string)lv.Source.ToList () [lv.SelectedItem!.Value]!);
|
|
|
}
|
|
|
|
|
|
+ #region ListView Tests (from ListViewTests.cs - parallelizable)
|
|
|
+
|
|
|
[Fact]
|
|
|
- public void ListView_CollectionNavigatorMatcher_KeybindingsOverrideNavigator ()
|
|
|
+ public void Constructors_Defaults ()
|
|
|
{
|
|
|
- ObservableCollection<string> source = new () { "apricot", "arm", "bat", "batman", "bates hotel", "candle" };
|
|
|
- ListView lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
+ var lv = new ListView ();
|
|
|
+ Assert.Null (lv.Source);
|
|
|
+ Assert.True (lv.CanFocus);
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+ Assert.False (lv.AllowsMultipleSelection);
|
|
|
|
|
|
- lv.SetFocus ();
|
|
|
+ lv = new () { Source = new ListWrapper<string> (["One", "Two", "Three"]) };
|
|
|
+ Assert.NotNull (lv.Source);
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
|
|
|
- lv.KeyBindings.Add (Key.B, Command.Down);
|
|
|
+ lv = new () { Source = new NewListDataSource () };
|
|
|
+ Assert.NotNull (lv.Source);
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
|
|
|
- Assert.Equal (-1, lv.SelectedItem);
|
|
|
+ lv = new ()
|
|
|
+ {
|
|
|
+ Y = 1, Width = 10, Height = 20, Source = new ListWrapper<string> (["One", "Two", "Three"])
|
|
|
+ };
|
|
|
+ Assert.NotNull (lv.Source);
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+ Assert.Equal (new (0, 1, 10, 20), lv.Frame);
|
|
|
|
|
|
- // Keys should be consumed to move down the navigation i.e. to apricot
|
|
|
- Assert.True (lv.NewKeyDownEvent (Key.B));
|
|
|
+ lv = new () { Y = 1, Width = 10, Height = 20, Source = new NewListDataSource () };
|
|
|
+ Assert.NotNull (lv.Source);
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+ Assert.Equal (new (0, 1, 10, 20), lv.Frame);
|
|
|
+ }
|
|
|
+
|
|
|
+ private class NewListDataSource : IListDataSource
|
|
|
+ {
|
|
|
+#pragma warning disable CS0067
|
|
|
+ public event NotifyCollectionChangedEventHandler? CollectionChanged;
|
|
|
+#pragma warning restore CS0067
|
|
|
+
|
|
|
+ public int Count => 0;
|
|
|
+ public int Length => 0;
|
|
|
+
|
|
|
+ public bool SuspendCollectionChangedEvent
|
|
|
+ {
|
|
|
+ get => throw new NotImplementedException ();
|
|
|
+ set => throw new NotImplementedException ();
|
|
|
+ }
|
|
|
+
|
|
|
+ public bool IsMarked (int item) { throw new NotImplementedException (); }
|
|
|
+
|
|
|
+ public void Render (
|
|
|
+ ListView container,
|
|
|
+ bool selected,
|
|
|
+ int item,
|
|
|
+ int col,
|
|
|
+ int line,
|
|
|
+ int width,
|
|
|
+ int viewportX = 0
|
|
|
+ )
|
|
|
+ {
|
|
|
+ throw new NotImplementedException ();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetMark (int item, bool value) { throw new NotImplementedException (); }
|
|
|
+ public IList ToList () { return new List<string> { "One", "Two", "Three" }; }
|
|
|
+
|
|
|
+ public void Dispose () { throw new NotImplementedException (); }
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void KeyBindings_Command ()
|
|
|
+ {
|
|
|
+ ObservableCollection<string> source = ["One", "Two", "Three"];
|
|
|
+ var lv = new ListView { Height = 2, AllowsMarking = true, Source = new ListWrapper<string> (source) };
|
|
|
+ lv.BeginInit ();
|
|
|
+ lv.EndInit ();
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.CursorDown));
|
|
|
+ Assert.Equal (0, lv.SelectedItem);
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.CursorUp));
|
|
|
+ Assert.Equal (0, lv.SelectedItem);
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.PageDown));
|
|
|
+ Assert.Equal (2, lv.SelectedItem);
|
|
|
+ Assert.Equal (2, lv.TopItem);
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.PageUp));
|
|
|
Assert.Equal (0, lv.SelectedItem);
|
|
|
+ Assert.Equal (0, lv.TopItem);
|
|
|
+ Assert.False (lv.Source.IsMarked (lv.SelectedItem!.Value));
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Space));
|
|
|
+ Assert.True (lv.Source.IsMarked (lv.SelectedItem!.Value));
|
|
|
+ var opened = false;
|
|
|
+ lv.OpenSelectedItem += (s, _) => opened = true;
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Enter));
|
|
|
+ Assert.True (opened);
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.End));
|
|
|
+ Assert.Equal (2, lv.SelectedItem);
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Home));
|
|
|
+ Assert.Equal (0, lv.SelectedItem);
|
|
|
+ }
|
|
|
|
|
|
- Assert.True (lv.NewKeyDownEvent (Key.B));
|
|
|
+ [Fact]
|
|
|
+ public void HotKey_Command_SetsFocus ()
|
|
|
+ {
|
|
|
+ var view = new ListView ();
|
|
|
+
|
|
|
+ view.CanFocus = true;
|
|
|
+ Assert.False (view.HasFocus);
|
|
|
+ view.InvokeCommand (Command.HotKey);
|
|
|
+ Assert.True (view.HasFocus);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void HotKey_Command_Does_Not_Accept ()
|
|
|
+ {
|
|
|
+ var listView = new ListView ();
|
|
|
+ var accepted = false;
|
|
|
+
|
|
|
+ listView.Accepting += OnAccepted;
|
|
|
+ listView.InvokeCommand (Command.HotKey);
|
|
|
+
|
|
|
+ Assert.False (accepted);
|
|
|
+
|
|
|
+ return;
|
|
|
+
|
|
|
+ void OnAccepted (object? sender, CommandEventArgs e) { accepted = true; }
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Accept_Command_Accepts_and_Opens_Selected_Item ()
|
|
|
+ {
|
|
|
+ ObservableCollection<string> source = ["One", "Two", "Three"];
|
|
|
+ var listView = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
+ listView.SelectedItem = 0;
|
|
|
+
|
|
|
+ var accepted = false;
|
|
|
+ var opened = false;
|
|
|
+ var selectedValue = string.Empty;
|
|
|
+
|
|
|
+ listView.Accepting += Accepted;
|
|
|
+ listView.OpenSelectedItem += OpenSelectedItem;
|
|
|
+
|
|
|
+ listView.InvokeCommand (Command.Accept);
|
|
|
+
|
|
|
+ Assert.True (accepted);
|
|
|
+ Assert.True (opened);
|
|
|
+ Assert.Equal (source [0], selectedValue);
|
|
|
+
|
|
|
+ return;
|
|
|
+
|
|
|
+ void OpenSelectedItem (object? sender, ListViewItemEventArgs e)
|
|
|
+ {
|
|
|
+ opened = true;
|
|
|
+ selectedValue = e.Value!.ToString ();
|
|
|
+ }
|
|
|
+
|
|
|
+ void Accepted (object? sender, CommandEventArgs e) { accepted = true; }
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Accept_Cancel_Event_Prevents_OpenSelectedItem ()
|
|
|
+ {
|
|
|
+ ObservableCollection<string> source = ["One", "Two", "Three"];
|
|
|
+ var listView = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
+ listView.SelectedItem = 0;
|
|
|
+
|
|
|
+ var accepted = false;
|
|
|
+ var opened = false;
|
|
|
+ var selectedValue = string.Empty;
|
|
|
+
|
|
|
+ listView.Accepting += Accepted;
|
|
|
+ listView.OpenSelectedItem += OpenSelectedItem;
|
|
|
+
|
|
|
+ listView.InvokeCommand (Command.Accept);
|
|
|
+
|
|
|
+ Assert.True (accepted);
|
|
|
+ Assert.False (opened);
|
|
|
+ Assert.Equal (string.Empty, selectedValue);
|
|
|
+
|
|
|
+ return;
|
|
|
+
|
|
|
+ void OpenSelectedItem (object? sender, ListViewItemEventArgs e)
|
|
|
+ {
|
|
|
+ opened = true;
|
|
|
+ selectedValue = e.Value!.ToString ();
|
|
|
+ }
|
|
|
+
|
|
|
+ void Accepted (object? sender, CommandEventArgs e)
|
|
|
+ {
|
|
|
+ accepted = true;
|
|
|
+ e.Handled = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void ListViewProcessKeyReturnValue_WithMultipleCommands ()
|
|
|
+ {
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (["One", "Two", "Three", "Four"]) };
|
|
|
+
|
|
|
+ Assert.NotNull (lv.Source);
|
|
|
+
|
|
|
+ // first item should be deselected by default
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+
|
|
|
+ // bind shift down to move down twice in control
|
|
|
+ lv.KeyBindings.Add (Key.CursorDown.WithShift, Command.Down, Command.Down);
|
|
|
+
|
|
|
+ Key ev = Key.CursorDown.WithShift;
|
|
|
+
|
|
|
+ Assert.True (lv.NewKeyDownEvent (ev), "The first time we move down 2 it should be possible");
|
|
|
+
|
|
|
+ // After moving down twice from null we should be at 'Two'
|
|
|
Assert.Equal (1, lv.SelectedItem);
|
|
|
|
|
|
- // There is no keybinding for Key.C so it hits collection navigator i.e. we jump to candle
|
|
|
- Assert.True (lv.NewKeyDownEvent (Key.C));
|
|
|
- Assert.Equal (5, lv.SelectedItem);
|
|
|
+ // clear the items
|
|
|
+ lv.SetSource<string> (null);
|
|
|
+
|
|
|
+ // Press key combo again - return should be false this time as none of the Commands are allowable
|
|
|
+ Assert.False (lv.NewKeyDownEvent (ev), "We cannot move down so will not respond to this");
|
|
|
}
|
|
|
|
|
|
[Fact]
|
|
|
- public void CollectionNavigatorMatcher_KeybindingsOverrideNavigator ()
|
|
|
+ public void AllowsMarking_True_SpaceWithShift_SelectsThenDown_SingleSelection ()
|
|
|
{
|
|
|
- ObservableCollection<string> source = new () { "apricot", "arm", "bat", "batman", "bates hotel", "candle" };
|
|
|
- ListView lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (["One", "Two", "Three"]) };
|
|
|
+ lv.AllowsMarking = true;
|
|
|
+ lv.AllowsMultipleSelection = false;
|
|
|
|
|
|
- lv.SetFocus ();
|
|
|
+ Assert.NotNull (lv.Source);
|
|
|
|
|
|
- lv.KeyBindings.Add (Key.B, Command.Down);
|
|
|
+ // first item should be deselected by default
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
|
|
|
- Assert.Equal (-1, lv.SelectedItem);
|
|
|
+ // nothing is ticked
|
|
|
+ Assert.False (lv.Source.IsMarked (0));
|
|
|
+ Assert.False (lv.Source.IsMarked (1));
|
|
|
+ Assert.False (lv.Source.IsMarked (2));
|
|
|
|
|
|
- // Keys should be consumed to move down the navigation i.e. to apricot
|
|
|
- Assert.True (lv.NewKeyDownEvent (Key.B));
|
|
|
+ // view should indicate that it has accepted and consumed the event
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
|
|
|
+
|
|
|
+ // first item should now be selected
|
|
|
Assert.Equal (0, lv.SelectedItem);
|
|
|
|
|
|
- Assert.True (lv.NewKeyDownEvent (Key.B));
|
|
|
+ // none of the items should be ticked
|
|
|
+ Assert.False (lv.Source.IsMarked (0));
|
|
|
+ Assert.False (lv.Source.IsMarked (1));
|
|
|
+ Assert.False (lv.Source.IsMarked (2));
|
|
|
+
|
|
|
+ // Press key combo again
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
|
|
|
+
|
|
|
+ // second item should now be selected
|
|
|
Assert.Equal (1, lv.SelectedItem);
|
|
|
|
|
|
- // There is no keybinding for Key.C so it hits collection navigator i.e. we jump to candle
|
|
|
- Assert.True (lv.NewKeyDownEvent (Key.C));
|
|
|
- Assert.Equal (5, lv.SelectedItem);
|
|
|
+ // first item only should be ticked
|
|
|
+ Assert.True (lv.Source.IsMarked (0));
|
|
|
+ Assert.False (lv.Source.IsMarked (1));
|
|
|
+ Assert.False (lv.Source.IsMarked (2));
|
|
|
+
|
|
|
+ // Press key combo again
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
|
|
|
+ Assert.Equal (2, lv.SelectedItem);
|
|
|
+ Assert.False (lv.Source.IsMarked (0));
|
|
|
+ Assert.True (lv.Source.IsMarked (1));
|
|
|
+ Assert.False (lv.Source.IsMarked (2));
|
|
|
+
|
|
|
+ // Press key combo again
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
|
|
|
+ Assert.Equal (2, lv.SelectedItem); // cannot move down any further
|
|
|
+ Assert.False (lv.Source.IsMarked (0));
|
|
|
+ Assert.False (lv.Source.IsMarked (1));
|
|
|
+ Assert.True (lv.Source.IsMarked (2)); // but can toggle marked
|
|
|
+
|
|
|
+ // Press key combo again
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
|
|
|
+ Assert.Equal (2, lv.SelectedItem); // cannot move down any further
|
|
|
+ Assert.False (lv.Source.IsMarked (0));
|
|
|
+ Assert.False (lv.Source.IsMarked (1));
|
|
|
+ Assert.False (lv.Source.IsMarked (2)); // untoggle toggle marked
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void AllowsMarking_True_SpaceWithShift_SelectsThenDown_MultipleSelection ()
|
|
|
+ {
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (["One", "Two", "Three"]) };
|
|
|
+ lv.AllowsMarking = true;
|
|
|
+ lv.AllowsMultipleSelection = true;
|
|
|
+
|
|
|
+ Assert.NotNull (lv.Source);
|
|
|
+
|
|
|
+ // first item should be deselected by default
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+
|
|
|
+ // nothing is ticked
|
|
|
+ Assert.False (lv.Source.IsMarked (0));
|
|
|
+ Assert.False (lv.Source.IsMarked (1));
|
|
|
+ Assert.False (lv.Source.IsMarked (2));
|
|
|
+
|
|
|
+ // view should indicate that it has accepted and consumed the event
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
|
|
|
+
|
|
|
+ // first item should now be selected
|
|
|
+ Assert.Equal (0, lv.SelectedItem);
|
|
|
+
|
|
|
+ // none of the items should be ticked
|
|
|
+ Assert.False (lv.Source.IsMarked (0));
|
|
|
+ Assert.False (lv.Source.IsMarked (1));
|
|
|
+ Assert.False (lv.Source.IsMarked (2));
|
|
|
+
|
|
|
+ // Press key combo again
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
|
|
|
+
|
|
|
+ // second item should now be selected
|
|
|
+ Assert.Equal (1, lv.SelectedItem);
|
|
|
+
|
|
|
+ // first item only should be ticked
|
|
|
+ Assert.True (lv.Source.IsMarked (0));
|
|
|
+ Assert.False (lv.Source.IsMarked (1));
|
|
|
+ Assert.False (lv.Source.IsMarked (2));
|
|
|
+
|
|
|
+ // Press key combo again
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
|
|
|
+ Assert.Equal (2, lv.SelectedItem);
|
|
|
+ Assert.True (lv.Source.IsMarked (0));
|
|
|
+ Assert.True (lv.Source.IsMarked (1));
|
|
|
+ Assert.False (lv.Source.IsMarked (2));
|
|
|
+
|
|
|
+ // Press key combo again
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
|
|
|
+ Assert.Equal (2, lv.SelectedItem); // cannot move down any further
|
|
|
+ Assert.True (lv.Source.IsMarked (0));
|
|
|
+ Assert.True (lv.Source.IsMarked (1));
|
|
|
+ Assert.True (lv.Source.IsMarked (2)); // but can toggle marked
|
|
|
+
|
|
|
+ // Press key combo again
|
|
|
+ Assert.True (lv.NewKeyDownEvent (Key.Space.WithShift));
|
|
|
+ Assert.Equal (2, lv.SelectedItem); // cannot move down any further
|
|
|
+ Assert.True (lv.Source.IsMarked (0));
|
|
|
+ Assert.True (lv.Source.IsMarked (1));
|
|
|
+ Assert.False (lv.Source.IsMarked (2)); // untoggle toggle marked
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void ListWrapper_StartsWith ()
|
|
|
+ {
|
|
|
+ ListWrapper<string> lw = new (["One", "Two", "Three"]);
|
|
|
+
|
|
|
+ Assert.Equal (1, lw.StartsWith ("t"));
|
|
|
+ Assert.Equal (1, lw.StartsWith ("tw"));
|
|
|
+ Assert.Equal (2, lw.StartsWith ("th"));
|
|
|
+ Assert.Equal (1, lw.StartsWith ("T"));
|
|
|
+ Assert.Equal (1, lw.StartsWith ("TW"));
|
|
|
+ Assert.Equal (2, lw.StartsWith ("TH"));
|
|
|
+
|
|
|
+ lw = new (["One", "Two", "Three"]);
|
|
|
+
|
|
|
+ Assert.Equal (1, lw.StartsWith ("t"));
|
|
|
+ Assert.Equal (1, lw.StartsWith ("tw"));
|
|
|
+ Assert.Equal (2, lw.StartsWith ("th"));
|
|
|
+ Assert.Equal (1, lw.StartsWith ("T"));
|
|
|
+ Assert.Equal (1, lw.StartsWith ("TW"));
|
|
|
+ Assert.Equal (2, lw.StartsWith ("TH"));
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void OnEnter_Does_Not_Throw_Exception ()
|
|
|
+ {
|
|
|
+ var lv = new ListView ();
|
|
|
+ var top = new View ();
|
|
|
+ top.Add (lv);
|
|
|
+ Exception exception = Record.Exception (() => lv.SetFocus ());
|
|
|
+ Assert.Null (exception);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void SelectedItem_Get_Set ()
|
|
|
+ {
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (["One", "Two", "Three"]) };
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+ Assert.Throws<ArgumentException> (() => lv.SelectedItem = 3);
|
|
|
+ Exception exception = Record.Exception (() => lv.SelectedItem = null);
|
|
|
+ Assert.Null (exception);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void SetSource_Preserves_ListWrapper_Instance_If_Not_Null ()
|
|
|
+ {
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (["One", "Two"]) };
|
|
|
+
|
|
|
+ Assert.NotNull (lv.Source);
|
|
|
+
|
|
|
+ lv.SetSource<string> (null);
|
|
|
+ Assert.NotNull (lv.Source);
|
|
|
+
|
|
|
+ lv.Source = null;
|
|
|
+ Assert.Null (lv.Source);
|
|
|
+
|
|
|
+ lv = new () { Source = new ListWrapper<string> (["One", "Two"]) };
|
|
|
+ Assert.NotNull (lv.Source);
|
|
|
+
|
|
|
+ lv.SetSourceAsync<string> (null);
|
|
|
+ Assert.NotNull (lv.Source);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void SettingEmptyKeybindingThrows ()
|
|
|
+ {
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (["One", "Two", "Three"]) };
|
|
|
+ Assert.Throws<ArgumentException> (() => lv.KeyBindings.Add (Key.Space));
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void CollectionChanged_Event ()
|
|
|
+ {
|
|
|
+ var added = 0;
|
|
|
+ var removed = 0;
|
|
|
+ ObservableCollection<string> source = [];
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
+
|
|
|
+ lv.CollectionChanged += (sender, args) =>
|
|
|
+ {
|
|
|
+ if (args.Action == NotifyCollectionChangedAction.Add)
|
|
|
+ {
|
|
|
+ added++;
|
|
|
+ }
|
|
|
+ else if (args.Action == NotifyCollectionChangedAction.Remove)
|
|
|
+ {
|
|
|
+ removed++;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ for (var i = 0; i < 3; i++)
|
|
|
+ {
|
|
|
+ source.Add ($"Item{i}");
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (3, added);
|
|
|
+ Assert.Equal (0, removed);
|
|
|
+
|
|
|
+ added = 0;
|
|
|
+
|
|
|
+ for (var i = 0; i < 3; i++)
|
|
|
+ {
|
|
|
+ source.Remove (source [0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (3, removed);
|
|
|
+ Assert.Empty (source);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void CollectionChanged_Event_Is_Only_Subscribed_Once ()
|
|
|
+ {
|
|
|
+ var added = 0;
|
|
|
+ var removed = 0;
|
|
|
+ var otherActions = 0;
|
|
|
+ IList<string> source1 = [];
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (new (source1)) };
|
|
|
+
|
|
|
+ lv.CollectionChanged += (sender, args) =>
|
|
|
+ {
|
|
|
+ if (args.Action == NotifyCollectionChangedAction.Add)
|
|
|
+ {
|
|
|
+ added++;
|
|
|
+ }
|
|
|
+ else if (args.Action == NotifyCollectionChangedAction.Remove)
|
|
|
+ {
|
|
|
+ removed++;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ otherActions++;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ ObservableCollection<string> source2 = [];
|
|
|
+ lv.Source = new ListWrapper<string> (source2);
|
|
|
+ ObservableCollection<string> source3 = [];
|
|
|
+ lv.Source = new ListWrapper<string> (source3);
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (0, removed);
|
|
|
+ Assert.Equal (0, otherActions);
|
|
|
+
|
|
|
+ for (var i = 0; i < 3; i++)
|
|
|
+ {
|
|
|
+ source1.Add ($"Item{i}");
|
|
|
+ source2.Add ($"Item{i}");
|
|
|
+ source3.Add ($"Item{i}");
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (3, added);
|
|
|
+ Assert.Equal (0, removed);
|
|
|
+ Assert.Equal (0, otherActions);
|
|
|
+
|
|
|
+ added = 0;
|
|
|
+
|
|
|
+ for (var i = 0; i < 3; i++)
|
|
|
+ {
|
|
|
+ source1.Remove (source1 [0]);
|
|
|
+ source2.Remove (source2 [0]);
|
|
|
+ source3.Remove (source3 [0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (3, removed);
|
|
|
+ Assert.Equal (0, otherActions);
|
|
|
+ Assert.Empty (source1);
|
|
|
+ Assert.Empty (source2);
|
|
|
+ Assert.Empty (source3);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void CollectionChanged_Event_UnSubscribe_Previous_If_New_Is_Null ()
|
|
|
+ {
|
|
|
+ var added = 0;
|
|
|
+ var removed = 0;
|
|
|
+ var otherActions = 0;
|
|
|
+ ObservableCollection<string> source1 = [];
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (source1) };
|
|
|
+
|
|
|
+ lv.CollectionChanged += (sender, args) =>
|
|
|
+ {
|
|
|
+ if (args.Action == NotifyCollectionChangedAction.Add)
|
|
|
+ {
|
|
|
+ added++;
|
|
|
+ }
|
|
|
+ else if (args.Action == NotifyCollectionChangedAction.Remove)
|
|
|
+ {
|
|
|
+ removed++;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ otherActions++;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ lv.Source = new ListWrapper<string> (null);
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (0, removed);
|
|
|
+ Assert.Equal (0, otherActions);
|
|
|
+
|
|
|
+ for (var i = 0; i < 3; i++)
|
|
|
+ {
|
|
|
+ source1.Add ($"Item{i}");
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (0, removed);
|
|
|
+ Assert.Equal (0, otherActions);
|
|
|
+
|
|
|
+ for (var i = 0; i < 3; i++)
|
|
|
+ {
|
|
|
+ source1.Remove (source1 [0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (0, removed);
|
|
|
+ Assert.Equal (0, otherActions);
|
|
|
+ Assert.Empty (source1);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void ListWrapper_CollectionChanged_Event_Is_Only_Subscribed_Once ()
|
|
|
+ {
|
|
|
+ var added = 0;
|
|
|
+ var removed = 0;
|
|
|
+ var otherActions = 0;
|
|
|
+ ObservableCollection<string> source1 = [];
|
|
|
+ ListWrapper<string> lw = new (source1);
|
|
|
+
|
|
|
+ lw.CollectionChanged += (sender, args) =>
|
|
|
+ {
|
|
|
+ if (args.Action == NotifyCollectionChangedAction.Add)
|
|
|
+ {
|
|
|
+ added++;
|
|
|
+ }
|
|
|
+ else if (args.Action == NotifyCollectionChangedAction.Remove)
|
|
|
+ {
|
|
|
+ removed++;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ otherActions++;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ ObservableCollection<string> source2 = [];
|
|
|
+ lw = new (source2);
|
|
|
+ ObservableCollection<string> source3 = [];
|
|
|
+ lw = new (source3);
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (0, removed);
|
|
|
+ Assert.Equal (0, otherActions);
|
|
|
+
|
|
|
+ for (var i = 0; i < 3; i++)
|
|
|
+ {
|
|
|
+ source1.Add ($"Item{i}");
|
|
|
+ source2.Add ($"Item{i}");
|
|
|
+ source3.Add ($"Item{i}");
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (3, added);
|
|
|
+ Assert.Equal (0, removed);
|
|
|
+ Assert.Equal (0, otherActions);
|
|
|
+
|
|
|
+ added = 0;
|
|
|
+
|
|
|
+ for (var i = 0; i < 3; i++)
|
|
|
+ {
|
|
|
+ source1.Remove (source1 [0]);
|
|
|
+ source2.Remove (source2 [0]);
|
|
|
+ source3.Remove (source3 [0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (3, removed);
|
|
|
+ Assert.Equal (0, otherActions);
|
|
|
+ Assert.Empty (source1);
|
|
|
+ Assert.Empty (source2);
|
|
|
+ Assert.Empty (source3);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void ListWrapper_CollectionChanged_Event_UnSubscribe_Previous_Is_Disposed ()
|
|
|
+ {
|
|
|
+ var added = 0;
|
|
|
+ var removed = 0;
|
|
|
+ var otherActions = 0;
|
|
|
+ ObservableCollection<string> source1 = [];
|
|
|
+ ListWrapper<string> lw = new (source1);
|
|
|
+
|
|
|
+ lw.CollectionChanged += Lw_CollectionChanged;
|
|
|
+
|
|
|
+ lw.Dispose ();
|
|
|
+ lw = new (null);
|
|
|
+ Assert.Equal (0, lw.Count);
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (0, removed);
|
|
|
+ Assert.Equal (0, otherActions);
|
|
|
+
|
|
|
+ for (var i = 0; i < 3; i++)
|
|
|
+ {
|
|
|
+ source1.Add ($"Item{i}");
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (0, removed);
|
|
|
+ Assert.Equal (0, otherActions);
|
|
|
+
|
|
|
+ for (var i = 0; i < 3; i++)
|
|
|
+ {
|
|
|
+ source1.Remove (source1 [0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (0, removed);
|
|
|
+ Assert.Equal (0, otherActions);
|
|
|
+ Assert.Empty (source1);
|
|
|
+
|
|
|
+ void Lw_CollectionChanged (object? sender, NotifyCollectionChangedEventArgs e)
|
|
|
+ {
|
|
|
+ if (e.Action == NotifyCollectionChangedAction.Add)
|
|
|
+ {
|
|
|
+ added++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void ListWrapper_SuspendCollectionChangedEvent_ResumeSuspendCollectionChangedEvent_Tests ()
|
|
|
+ {
|
|
|
+ var added = 0;
|
|
|
+ ObservableCollection<string> source = [];
|
|
|
+ ListWrapper<string> lw = new (source);
|
|
|
+
|
|
|
+ lw.CollectionChanged += Lw_CollectionChanged;
|
|
|
+
|
|
|
+ lw.SuspendCollectionChangedEvent = true;
|
|
|
+
|
|
|
+ for (var i = 0; i < 3; i++)
|
|
|
+ {
|
|
|
+ source.Add ($"Item{i}");
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (3, lw.Count);
|
|
|
+ Assert.Equal (3, source.Count);
|
|
|
+
|
|
|
+ lw.SuspendCollectionChangedEvent = false;
|
|
|
+
|
|
|
+ for (var i = 3; i < 6; i++)
|
|
|
+ {
|
|
|
+ source.Add ($"Item{i}");
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (3, added);
|
|
|
+ Assert.Equal (6, lw.Count);
|
|
|
+ Assert.Equal (6, source.Count);
|
|
|
+
|
|
|
+ void Lw_CollectionChanged (object? sender, NotifyCollectionChangedEventArgs e)
|
|
|
+ {
|
|
|
+ if (e.Action == NotifyCollectionChangedAction.Add)
|
|
|
+ {
|
|
|
+ added++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void ListView_SuspendCollectionChangedEvent_ResumeSuspendCollectionChangedEvent_Tests ()
|
|
|
+ {
|
|
|
+ var added = 0;
|
|
|
+ ObservableCollection<string> source = [];
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
+
|
|
|
+ lv.CollectionChanged += Lw_CollectionChanged;
|
|
|
+
|
|
|
+ lv.SuspendCollectionChangedEvent ();
|
|
|
+
|
|
|
+ for (var i = 0; i < 3; i++)
|
|
|
+ {
|
|
|
+ source.Add ($"Item{i}");
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (0, added);
|
|
|
+ Assert.Equal (3, lv.Source.Count);
|
|
|
+ Assert.Equal (3, source.Count);
|
|
|
+
|
|
|
+ lv.ResumeSuspendCollectionChangedEvent ();
|
|
|
+
|
|
|
+ for (var i = 3; i < 6; i++)
|
|
|
+ {
|
|
|
+ source.Add ($"Item{i}");
|
|
|
+ }
|
|
|
+
|
|
|
+ Assert.Equal (3, added);
|
|
|
+ Assert.Equal (6, lv.Source.Count);
|
|
|
+ Assert.Equal (6, source.Count);
|
|
|
+
|
|
|
+ void Lw_CollectionChanged (object? sender, NotifyCollectionChangedEventArgs e)
|
|
|
+ {
|
|
|
+ if (e.Action == NotifyCollectionChangedAction.Add)
|
|
|
+ {
|
|
|
+ added++;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Clicking_On_Border_Is_Ignored ()
|
|
|
+ {
|
|
|
+ IApplication? app = Application.Create ();
|
|
|
+ app.Init ("fake");
|
|
|
+
|
|
|
+ var selected = "";
|
|
|
+
|
|
|
+ var lv = new ListView
|
|
|
+ {
|
|
|
+ Height = 5,
|
|
|
+ Width = 7,
|
|
|
+ BorderStyle = LineStyle.Single
|
|
|
+ };
|
|
|
+ lv.SetSource (["One", "Two", "Three", "Four"]);
|
|
|
+ lv.SelectedItemChanged += (s, e) => selected = e.Value.ToString ();
|
|
|
+ var top = new Toplevel ();
|
|
|
+ top.Add (lv);
|
|
|
+ app.Begin (top);
|
|
|
+
|
|
|
+ //AutoInitShutdownAttribute.RunIteration ();
|
|
|
+
|
|
|
+ Assert.Equal (new (1), lv.Border!.Thickness);
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+ Assert.Equal ("", lv.Text);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+┌─────┐
|
|
|
+│One │
|
|
|
+│Two │
|
|
|
+│Three│
|
|
|
+└─────┘",
|
|
|
+ _output, app?.Driver);
|
|
|
+
|
|
|
+ app?.Mouse.RaiseMouseEvent (new () { ScreenPosition = new (0, 0), Flags = MouseFlags.Button1Clicked });
|
|
|
+ Assert.Equal ("", selected);
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+
|
|
|
+ app?.Mouse.RaiseMouseEvent (
|
|
|
+ new ()
|
|
|
+ {
|
|
|
+ ScreenPosition = new (1, 1), Flags = MouseFlags.Button1Clicked
|
|
|
+ });
|
|
|
+ Assert.Equal ("One", selected);
|
|
|
+ Assert.Equal (0, lv.SelectedItem);
|
|
|
+
|
|
|
+ app?.Mouse.RaiseMouseEvent (
|
|
|
+ new ()
|
|
|
+ {
|
|
|
+ ScreenPosition = new (1, 2), Flags = MouseFlags.Button1Clicked
|
|
|
+ });
|
|
|
+ Assert.Equal ("Two", selected);
|
|
|
+ Assert.Equal (1, lv.SelectedItem);
|
|
|
+
|
|
|
+ app?.Mouse.RaiseMouseEvent (
|
|
|
+ new ()
|
|
|
+ {
|
|
|
+ ScreenPosition = new (1, 3), Flags = MouseFlags.Button1Clicked
|
|
|
+ });
|
|
|
+ Assert.Equal ("Three", selected);
|
|
|
+ Assert.Equal (2, lv.SelectedItem);
|
|
|
+
|
|
|
+ app?.Mouse.RaiseMouseEvent (
|
|
|
+ new ()
|
|
|
+ {
|
|
|
+ ScreenPosition = new (1, 4), Flags = MouseFlags.Button1Clicked
|
|
|
+ });
|
|
|
+ Assert.Equal ("Three", selected);
|
|
|
+ Assert.Equal (2, lv.SelectedItem);
|
|
|
+ top.Dispose ();
|
|
|
+
|
|
|
+ app.Shutdown ();
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Ensures_Visibility_SelectedItem_On_MoveDown_And_MoveUp ()
|
|
|
+ {
|
|
|
+ IApplication? app = Application.Create ();
|
|
|
+ app.Init ("fake");
|
|
|
+ app.Driver?.SetScreenSize (12, 12);
|
|
|
+
|
|
|
+ ObservableCollection<string> source = [];
|
|
|
+
|
|
|
+ for (var i = 0; i < 20; i++)
|
|
|
+ {
|
|
|
+ source.Add ($"Line{i}");
|
|
|
+ }
|
|
|
+
|
|
|
+ var lv = new ListView { Width = Dim.Fill (), Height = Dim.Fill (), Source = new ListWrapper<string> (source) };
|
|
|
+ var win = new Window ();
|
|
|
+ win.Add (lv);
|
|
|
+ var top = new Toplevel ();
|
|
|
+ top.Add (win);
|
|
|
+ app.Begin (top);
|
|
|
+
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+┌──────────┐
|
|
|
+│Line0 │
|
|
|
+│Line1 │
|
|
|
+│Line2 │
|
|
|
+│Line3 │
|
|
|
+│Line4 │
|
|
|
+│Line5 │
|
|
|
+│Line6 │
|
|
|
+│Line7 │
|
|
|
+│Line8 │
|
|
|
+│Line9 │
|
|
|
+└──────────┘",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+
|
|
|
+ Assert.True (lv.ScrollVertical (10));
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+┌──────────┐
|
|
|
+│Line10 │
|
|
|
+│Line11 │
|
|
|
+│Line12 │
|
|
|
+│Line13 │
|
|
|
+│Line14 │
|
|
|
+│Line15 │
|
|
|
+│Line16 │
|
|
|
+│Line17 │
|
|
|
+│Line18 │
|
|
|
+│Line19 │
|
|
|
+└──────────┘",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+
|
|
|
+ Assert.True (lv.MoveDown ());
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (0, lv.SelectedItem);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+┌──────────┐
|
|
|
+│Line0 │
|
|
|
+│Line1 │
|
|
|
+│Line2 │
|
|
|
+│Line3 │
|
|
|
+│Line4 │
|
|
|
+│Line5 │
|
|
|
+│Line6 │
|
|
|
+│Line7 │
|
|
|
+│Line8 │
|
|
|
+│Line9 │
|
|
|
+└──────────┘",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+
|
|
|
+ Assert.True (lv.MoveEnd ());
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (19, lv.SelectedItem);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+┌──────────┐
|
|
|
+│Line10 │
|
|
|
+│Line11 │
|
|
|
+│Line12 │
|
|
|
+│Line13 │
|
|
|
+│Line14 │
|
|
|
+│Line15 │
|
|
|
+│Line16 │
|
|
|
+│Line17 │
|
|
|
+│Line18 │
|
|
|
+│Line19 │
|
|
|
+└──────────┘",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+
|
|
|
+ Assert.True (lv.ScrollVertical (-20));
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (19, lv.SelectedItem);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+┌──────────┐
|
|
|
+│Line0 │
|
|
|
+│Line1 │
|
|
|
+│Line2 │
|
|
|
+│Line3 │
|
|
|
+│Line4 │
|
|
|
+│Line5 │
|
|
|
+│Line6 │
|
|
|
+│Line7 │
|
|
|
+│Line8 │
|
|
|
+│Line9 │
|
|
|
+└──────────┘",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+
|
|
|
+ Assert.True (lv.MoveDown ());
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (19, lv.SelectedItem);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+┌──────────┐
|
|
|
+│Line10 │
|
|
|
+│Line11 │
|
|
|
+│Line12 │
|
|
|
+│Line13 │
|
|
|
+│Line14 │
|
|
|
+│Line15 │
|
|
|
+│Line16 │
|
|
|
+│Line17 │
|
|
|
+│Line18 │
|
|
|
+│Line19 │
|
|
|
+└──────────┘",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+
|
|
|
+ Assert.True (lv.ScrollVertical (-20));
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (19, lv.SelectedItem);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+┌──────────┐
|
|
|
+│Line0 │
|
|
|
+│Line1 │
|
|
|
+│Line2 │
|
|
|
+│Line3 │
|
|
|
+│Line4 │
|
|
|
+│Line5 │
|
|
|
+│Line6 │
|
|
|
+│Line7 │
|
|
|
+│Line8 │
|
|
|
+│Line9 │
|
|
|
+└──────────┘",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+
|
|
|
+ Assert.True (lv.MoveDown ());
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (19, lv.SelectedItem);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+┌──────────┐
|
|
|
+│Line10 │
|
|
|
+│Line11 │
|
|
|
+│Line12 │
|
|
|
+│Line13 │
|
|
|
+│Line14 │
|
|
|
+│Line15 │
|
|
|
+│Line16 │
|
|
|
+│Line17 │
|
|
|
+│Line18 │
|
|
|
+│Line19 │
|
|
|
+└──────────┘",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+
|
|
|
+ Assert.True (lv.MoveHome ());
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (0, lv.SelectedItem);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+┌──────────┐
|
|
|
+│Line0 │
|
|
|
+│Line1 │
|
|
|
+│Line2 │
|
|
|
+│Line3 │
|
|
|
+│Line4 │
|
|
|
+│Line5 │
|
|
|
+│Line6 │
|
|
|
+│Line7 │
|
|
|
+│Line8 │
|
|
|
+│Line9 │
|
|
|
+└──────────┘",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+
|
|
|
+ Assert.True (lv.ScrollVertical (20));
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (0, lv.SelectedItem);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+┌──────────┐
|
|
|
+│Line19 │
|
|
|
+│ │
|
|
|
+│ │
|
|
|
+│ │
|
|
|
+│ │
|
|
|
+│ │
|
|
|
+│ │
|
|
|
+│ │
|
|
|
+│ │
|
|
|
+│ │
|
|
|
+└──────────┘",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+
|
|
|
+ Assert.True (lv.MoveUp ());
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (0, lv.SelectedItem);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+┌──────────┐
|
|
|
+│Line0 │
|
|
|
+│Line1 │
|
|
|
+│Line2 │
|
|
|
+│Line3 │
|
|
|
+│Line4 │
|
|
|
+│Line5 │
|
|
|
+│Line6 │
|
|
|
+│Line7 │
|
|
|
+│Line8 │
|
|
|
+│Line9 │
|
|
|
+└──────────┘",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+ top.Dispose ();
|
|
|
+ app.Shutdown ();
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void EnsureSelectedItemVisible_SelectedItem ()
|
|
|
+ {
|
|
|
+ IApplication? app = Application.Create ();
|
|
|
+ app.Init ("fake");
|
|
|
+ app.Driver?.SetScreenSize (12, 12);
|
|
|
+
|
|
|
+ ObservableCollection<string> source = [];
|
|
|
+
|
|
|
+ for (var i = 0; i < 10; i++)
|
|
|
+ {
|
|
|
+ source.Add ($"Item {i}");
|
|
|
+ }
|
|
|
+
|
|
|
+ var lv = new ListView { Width = 10, Height = 5, Source = new ListWrapper<string> (source) };
|
|
|
+ var top = new Toplevel ();
|
|
|
+ top.Add (lv);
|
|
|
+ app.Begin (top);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+Item 0
|
|
|
+Item 1
|
|
|
+Item 2
|
|
|
+Item 3
|
|
|
+Item 4",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+
|
|
|
+ // EnsureSelectedItemVisible is auto enabled on the OnSelectedChanged
|
|
|
+ lv.SelectedItem = 6;
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+Item 2
|
|
|
+Item 3
|
|
|
+Item 4
|
|
|
+Item 5
|
|
|
+Item 6",
|
|
|
+ _output, app.Driver
|
|
|
+ );
|
|
|
+ top.Dispose ();
|
|
|
+ app.Shutdown ();
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void EnsureSelectedItemVisible_Top ()
|
|
|
+ {
|
|
|
+ IApplication? app = Application.Create ();
|
|
|
+ app.Init ("fake");
|
|
|
+ IDriver? driver = app.Driver;
|
|
|
+ driver.SetScreenSize (8, 2);
|
|
|
+
|
|
|
+ ObservableCollection<string> source = ["First", "Second"];
|
|
|
+ var lv = new ListView { Width = Dim.Fill (), Height = 1, Source = new ListWrapper<string> (source) };
|
|
|
+ lv.SelectedItem = 1;
|
|
|
+ var top = new Toplevel ();
|
|
|
+ top.Add (lv);
|
|
|
+ app.Begin (top);
|
|
|
+
|
|
|
+ Assert.Equal ("Second ", GetContents (0));
|
|
|
+ Assert.Equal (new (' ', 7), GetContents (1));
|
|
|
+
|
|
|
+ lv.MoveUp ();
|
|
|
+ lv.Draw ();
|
|
|
+
|
|
|
+ Assert.Equal ("First ", GetContents (0));
|
|
|
+ Assert.Equal (new (' ', 7), GetContents (1));
|
|
|
+
|
|
|
+ string GetContents (int line)
|
|
|
+ {
|
|
|
+ var item = "";
|
|
|
+
|
|
|
+ for (var i = 0; i < 7; i++)
|
|
|
+ {
|
|
|
+ item += app.Driver?.Contents [line, i].Rune;
|
|
|
+ }
|
|
|
+
|
|
|
+ return item;
|
|
|
+ }
|
|
|
+
|
|
|
+ top.Dispose ();
|
|
|
+ app.Shutdown ();
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void LeftItem_TopItem_Tests ()
|
|
|
+ {
|
|
|
+ IApplication? app = Application.Create ();
|
|
|
+ app.Init ("fake");
|
|
|
+ app.Driver?.SetScreenSize (12, 12);
|
|
|
+
|
|
|
+ ObservableCollection<string> source = [];
|
|
|
+
|
|
|
+ for (var i = 0; i < 5; i++)
|
|
|
+ {
|
|
|
+ source.Add ($"Item {i}");
|
|
|
+ }
|
|
|
+
|
|
|
+ var lv = new ListView
|
|
|
+ {
|
|
|
+ X = 1,
|
|
|
+ Source = new ListWrapper<string> (source)
|
|
|
+ };
|
|
|
+ lv.Height = lv.Source.Count;
|
|
|
+ lv.Width = lv.MaxLength;
|
|
|
+ var top = new Toplevel ();
|
|
|
+ top.Add (lv);
|
|
|
+ app.Begin (top);
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+ Item 0
|
|
|
+ Item 1
|
|
|
+ Item 2
|
|
|
+ Item 3
|
|
|
+ Item 4",
|
|
|
+ _output, app.Driver);
|
|
|
+
|
|
|
+ lv.LeftItem = 1;
|
|
|
+ lv.TopItem = 1;
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+ tem 1
|
|
|
+ tem 2
|
|
|
+ tem 3
|
|
|
+ tem 4",
|
|
|
+ _output, app.Driver);
|
|
|
+ top.Dispose ();
|
|
|
+ app.Shutdown ();
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void RowRender_Event ()
|
|
|
+ {
|
|
|
+ IApplication? app = Application.Create ();
|
|
|
+ app.Init ("fake");
|
|
|
+
|
|
|
+ var rendered = false;
|
|
|
+ ObservableCollection<string> source = ["one", "two", "three"];
|
|
|
+ var lv = new ListView { Width = Dim.Fill (), Height = Dim.Fill () };
|
|
|
+ lv.RowRender += (s, _) => rendered = true;
|
|
|
+ var top = new Toplevel ();
|
|
|
+ top.Add (lv);
|
|
|
+ app.Begin (top);
|
|
|
+ Assert.False (rendered);
|
|
|
+
|
|
|
+ lv.SetSource (source);
|
|
|
+ lv.Draw ();
|
|
|
+ Assert.True (rendered);
|
|
|
+ top.Dispose ();
|
|
|
+ app.Shutdown ();
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Vertical_ScrollBar_Hides_And_Shows_As_Needed ()
|
|
|
+ {
|
|
|
+ IApplication? app = Application.Create ();
|
|
|
+ app.Init ("fake");
|
|
|
+
|
|
|
+ var lv = new ListView
|
|
|
+ {
|
|
|
+ Width = 10,
|
|
|
+ Height = 3
|
|
|
+ };
|
|
|
+ lv.VerticalScrollBar.AutoShow = true;
|
|
|
+ lv.SetSource (["One", "Two", "Three", "Four", "Five"]);
|
|
|
+ var top = new Toplevel ();
|
|
|
+ top.Add (lv);
|
|
|
+ app.Begin (top);
|
|
|
+
|
|
|
+ Assert.True (lv.VerticalScrollBar.Visible);
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+One ▲
|
|
|
+Two █
|
|
|
+Three ▼",
|
|
|
+ _output, app?.Driver);
|
|
|
+
|
|
|
+ lv.Height = 5;
|
|
|
+ app?.LayoutAndDraw ();
|
|
|
+
|
|
|
+ Assert.False (lv.VerticalScrollBar.Visible);
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+One
|
|
|
+Two
|
|
|
+Three
|
|
|
+Four
|
|
|
+Five ",
|
|
|
+ _output, app?.Driver);
|
|
|
+ top.Dispose ();
|
|
|
+ app?.Shutdown ();
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Mouse_Wheel_Scrolls ()
|
|
|
+ {
|
|
|
+ IApplication? app = Application.Create ();
|
|
|
+ app.Init ("fake");
|
|
|
+
|
|
|
+ var lv = new ListView
|
|
|
+ {
|
|
|
+ Width = 10,
|
|
|
+ Height = 3,
|
|
|
+ };
|
|
|
+ lv.SetSource (["One", "Two", "Three", "Four", "Five"]);
|
|
|
+ var top = new Toplevel ();
|
|
|
+ top.Add (lv);
|
|
|
+ app.Begin (top);
|
|
|
+
|
|
|
+ // Initially, we are at the top.
|
|
|
+ Assert.Equal (0, lv.TopItem);
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+One
|
|
|
+Two
|
|
|
+Three",
|
|
|
+ _output, app?.Driver);
|
|
|
+
|
|
|
+ // Scroll down
|
|
|
+ app.Mouse.RaiseMouseEvent (new () { ScreenPosition = new (0, 0), Flags = MouseFlags.WheeledDown });
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (1, lv.TopItem);
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+Two
|
|
|
+Three
|
|
|
+Four ",
|
|
|
+ _output, app?.Driver);
|
|
|
+
|
|
|
+ // Scroll up
|
|
|
+ app.Mouse.RaiseMouseEvent (new () { ScreenPosition = new (0, 0), Flags = MouseFlags.WheeledUp });
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (0, lv.TopItem);
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+One
|
|
|
+Two
|
|
|
+Three",
|
|
|
+ _output, app?.Driver);
|
|
|
+
|
|
|
+ top.Dispose ();
|
|
|
+ app.Shutdown ();
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void SelectedItem_With_Source_Null_Does_Nothing ()
|
|
|
+ {
|
|
|
+ var lv = new ListView ();
|
|
|
+ Assert.Null (lv.Source);
|
|
|
+
|
|
|
+ // should not throw
|
|
|
+ lv.SelectedItem = 0;
|
|
|
+
|
|
|
+ Assert.Null (lv.SelectedItem);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Horizontal_Scroll ()
|
|
|
+ {
|
|
|
+ IApplication? app = Application.Create ();
|
|
|
+ app.Init ("fake");
|
|
|
+
|
|
|
+ var lv = new ListView
|
|
|
+ {
|
|
|
+ Width = 10,
|
|
|
+ Height = 3,
|
|
|
+ };
|
|
|
+ lv.SetSource (["One", "Two", "Three - long", "Four", "Five"]);
|
|
|
+ var top = new Toplevel ();
|
|
|
+ top.Add (lv);
|
|
|
+ app.Begin (top);
|
|
|
+
|
|
|
+ Assert.Equal (0, lv.LeftItem);
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+One
|
|
|
+Two
|
|
|
+Three - lo",
|
|
|
+ _output, app?.Driver);
|
|
|
+
|
|
|
+ lv.ScrollHorizontal (1);
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (1, lv.LeftItem);
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+ne
|
|
|
+wo
|
|
|
+hree - lon",
|
|
|
+ _output, app?.Driver);
|
|
|
+
|
|
|
+ // Scroll right with mouse
|
|
|
+ app.Mouse.RaiseMouseEvent (new () { ScreenPosition = new (0, 0), Flags = MouseFlags.WheeledRight });
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (2, lv.LeftItem);
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+e
|
|
|
+o
|
|
|
+ree - long",
|
|
|
+ _output, app?.Driver);
|
|
|
+
|
|
|
+ // Scroll left with mouse
|
|
|
+ app.Mouse.RaiseMouseEvent (new () { ScreenPosition = new (0, 0), Flags = MouseFlags.WheeledLeft });
|
|
|
+ app.LayoutAndDraw ();
|
|
|
+ Assert.Equal (1, lv.LeftItem);
|
|
|
+ DriverAssert.AssertDriverContentsWithFrameAre (
|
|
|
+ @"
|
|
|
+ne
|
|
|
+wo
|
|
|
+hree - lon",
|
|
|
+ _output, app?.Driver);
|
|
|
+
|
|
|
+ top.Dispose ();
|
|
|
+ app.Shutdown ();
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public async Task SetSourceAsync_SetsSource ()
|
|
|
+ {
|
|
|
+ var lv = new ListView ();
|
|
|
+ var source = new ObservableCollection<string> { "One", "Two", "Three" };
|
|
|
+
|
|
|
+ await lv.SetSourceAsync (source);
|
|
|
+
|
|
|
+ Assert.NotNull (lv.Source);
|
|
|
+ Assert.Equal (3, lv.Source.Count);
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void AllowsMultipleSelection_Set_To_False_Unmarks_All_But_Selected ()
|
|
|
+ {
|
|
|
+ var lv = new ListView { AllowsMarking = true, AllowsMultipleSelection = true };
|
|
|
+ var source = new ListWrapper<string> (["One", "Two", "Three"]);
|
|
|
+ lv.Source = source;
|
|
|
+
|
|
|
+ lv.SelectedItem = 0;
|
|
|
+ source.SetMark (0, true);
|
|
|
+ source.SetMark (1, true);
|
|
|
+ source.SetMark (2, true);
|
|
|
+
|
|
|
+ Assert.True (source.IsMarked (0));
|
|
|
+ Assert.True (source.IsMarked (1));
|
|
|
+ Assert.True (source.IsMarked (2));
|
|
|
+
|
|
|
+ lv.AllowsMultipleSelection = false;
|
|
|
+
|
|
|
+ Assert.True (source.IsMarked (0));
|
|
|
+ Assert.False (source.IsMarked (1));
|
|
|
+ Assert.False (source.IsMarked (2));
|
|
|
+ }
|
|
|
+
|
|
|
+ [Fact]
|
|
|
+ public void Source_CollectionChanged_Remove ()
|
|
|
+ {
|
|
|
+ var source = new ObservableCollection<string> { "One", "Two", "Three" };
|
|
|
+ var lv = new ListView { Source = new ListWrapper<string> (source) };
|
|
|
+
|
|
|
+ lv.SelectedItem = 2;
|
|
|
+ Assert.Equal (2, lv.SelectedItem);
|
|
|
+ Assert.Equal (3, lv.Source.Count);
|
|
|
+
|
|
|
+ source.RemoveAt (0);
|
|
|
+
|
|
|
+ Assert.Equal (2, lv.Source.Count);
|
|
|
+ Assert.Equal (1, lv.SelectedItem);
|
|
|
+
|
|
|
+ source.RemoveAt (1);
|
|
|
+ Assert.Equal (1, lv.Source.Count);
|
|
|
+ Assert.Equal (0, lv.SelectedItem);
|
|
|
}
|
|
|
}
|