Browse Source

Added Move and MoveRange to AvaloniaList.

Also added test for replace operation.
Steven Kirk 9 years ago
parent
commit
05f836c4c3

+ 51 - 0
src/Avalonia.Base/Collections/AvaloniaList.cs

@@ -319,6 +319,57 @@ namespace Avalonia.Collections
             }
         }
 
+        /// <summary>
+        /// Moves an item to a new index.
+        /// </summary>
+        /// <param name="oldIndex">The index of the item to move.</param>
+        /// <param name="newIndex">The index to move the item to.</param>
+        public void Move(int oldIndex, int newIndex)
+        {
+            var item = this[oldIndex];
+            _inner.RemoveAt(oldIndex);
+            _inner.Insert(newIndex, item);
+
+            if (_collectionChanged != null)
+            {
+                var e = new NotifyCollectionChangedEventArgs(
+                    NotifyCollectionChangedAction.Move,
+                    item,
+                    newIndex,
+                    oldIndex);
+                _collectionChanged(this, e);
+            }
+        }
+
+        /// <summary>
+        /// Moves multiple items to a new index.
+        /// </summary>
+        /// <param name="oldIndex">The first index of the items to move.</param>
+        /// <param name="count">The number of items to move.</param>
+        /// <param name="newIndex">The index to move the items to.</param>
+        public void MoveRange(int oldIndex, int count, int newIndex)
+        {
+            var items = _inner.GetRange(oldIndex, count);
+            _inner.RemoveRange(oldIndex, count);
+
+            if (newIndex > oldIndex)
+            {
+                newIndex -= count;
+            }
+
+            _inner.InsertRange(newIndex, items);
+
+            if (_collectionChanged != null)
+            {
+                var e = new NotifyCollectionChangedEventArgs(
+                    NotifyCollectionChangedAction.Move,
+                    items,
+                    newIndex,
+                    oldIndex);
+                _collectionChanged(this, e);
+            }
+        }
+
         /// <summary>
         /// Removes an item from the collection.
         /// </summary>

+ 99 - 0
tests/Avalonia.Base.UnitTests/Collections/AvaloniaListTests.cs

@@ -53,6 +53,36 @@ namespace Avalonia.Base.UnitTests.Collections
             Assert.Throws<ArgumentOutOfRangeException>(() => target.InsertRange(1, new List<int>() { 1 }));
         }
 
+        [Fact]
+        public void Move_Should_Update_Collection()
+        {
+            var target = new AvaloniaList<int>(new[] { 1, 2, 3 });
+
+            target.Move(2, 0);
+
+            Assert.Equal(new[] { 3, 1, 2 }, target);
+        }
+
+        [Fact]
+        public void MoveRange_Should_Update_Collection()
+        {
+            var target = new AvaloniaList<int>(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
+
+            target.MoveRange(4, 3, 0);
+
+            Assert.Equal(new[] { 5, 6, 7, 1, 2, 3, 4, 8, 9, 10 }, target);
+        }
+
+        [Fact]
+        public void MoveRange_Can_Move_To_End()
+        {
+            var target = new AvaloniaList<int>(new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });
+
+            target.MoveRange(0, 5, 10);
+
+            Assert.Equal(new[] { 6, 7, 8, 9, 10, 1, 2, 3, 4, 5 }, target);
+        }
+
         [Fact]
         public void Adding_Item_Should_Raise_CollectionChanged()
         {
@@ -95,6 +125,29 @@ namespace Avalonia.Base.UnitTests.Collections
             Assert.True(raised);
         }
 
+        [Fact]
+        public void Replacing_Item_Should_Raise_CollectionChanged()
+        {
+            var target = new AvaloniaList<int>(new[] { 1, 2 });
+            var raised = false;
+
+            target.CollectionChanged += (s, e) =>
+            {
+                Assert.Equal(target, s);
+                Assert.Equal(NotifyCollectionChangedAction.Replace, e.Action);
+                Assert.Equal(new[] { 2 }, e.OldItems.Cast<int>());
+                Assert.Equal(new[] { 3 }, e.NewItems.Cast<int>());
+                Assert.Equal(1, e.OldStartingIndex);
+                Assert.Equal(1, e.NewStartingIndex);
+
+                raised = true;
+            };
+
+            target[1] = 3;
+
+            Assert.True(raised);
+        }
+
         [Fact]
         public void Inserting_Item_Should_Raise_CollectionChanged()
         {
@@ -158,6 +211,52 @@ namespace Avalonia.Base.UnitTests.Collections
             Assert.True(raised);
         }
 
+        [Fact]
+        public void Moving_Item_Should_Raise_CollectionChanged()
+        {
+            var target = new AvaloniaList<int>(new[] { 1, 2, 3 });
+            var raised = false;
+
+            target.CollectionChanged += (s, e) =>
+            {
+                Assert.Equal(target, s);
+                Assert.Equal(NotifyCollectionChangedAction.Move, e.Action);
+                Assert.Equal(new[] { 3 }, e.OldItems.Cast<int>());
+                Assert.Equal(new[] { 3 }, e.NewItems.Cast<int>());
+                Assert.Equal(2, e.OldStartingIndex);
+                Assert.Equal(0, e.NewStartingIndex);
+
+                raised = true;
+            };
+
+            target.Move(2, 0);
+
+            Assert.True(raised);
+        }
+
+        [Fact]
+        public void Moving_Items_Should_Raise_CollectionChanged()
+        {
+            var target = new AvaloniaList<int>(new[] { 1, 2, 3 });
+            var raised = false;
+
+            target.CollectionChanged += (s, e) =>
+            {
+                Assert.Equal(target, s);
+                Assert.Equal(NotifyCollectionChangedAction.Move, e.Action);
+                Assert.Equal(new[] { 2, 3 }, e.OldItems.Cast<int>());
+                Assert.Equal(new[] { 2, 3 }, e.NewItems.Cast<int>());
+                Assert.Equal(1, e.OldStartingIndex);
+                Assert.Equal(0, e.NewStartingIndex);
+
+                raised = true;
+            };
+
+            target.MoveRange(1, 2, 0);
+
+            Assert.True(raised);
+        }
+
         [Fact]
         public void Clearing_Items_Should_Raise_CollectionChanged_Reset()
         {