From 41e434e13bd3ce792e17bacfe69cc9d8b7ea778c Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Sat, 2 May 2015 18:44:25 +0200 Subject: [PATCH] Added SelectedItemsControl.SelectedIndex --- .../Primitives/SelectingItemsControl.cs | 78 ++++++++- .../Perspex.Controls.UnitTests.csproj | 2 +- .../Primitives/SelectingItemsControlTests.cs | 154 ++++++++++++++++++ .../SelectingItemsControlTests.cs | 34 ---- 4 files changed, 232 insertions(+), 36 deletions(-) create mode 100644 Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs delete mode 100644 Tests/Perspex.Controls.UnitTests/SelectingItemsControlTests.cs diff --git a/Perspex.Controls/Primitives/SelectingItemsControl.cs b/Perspex.Controls/Primitives/SelectingItemsControl.cs index d4d26f9d69..70421ca0e8 100644 --- a/Perspex.Controls/Primitives/SelectingItemsControl.cs +++ b/Perspex.Controls/Primitives/SelectingItemsControl.cs @@ -11,9 +11,13 @@ namespace Perspex.Controls.Primitives using System.Linq; using Perspex.Input; using Perspex.VisualTree; + using System.Collections.Generic; public abstract class SelectingItemsControl : ItemsControl { + public static readonly PerspexProperty SelectedIndexProperty = + PerspexProperty.Register("SelectedIndex", coerce: CoerceSelectedIndex); + public static readonly PerspexProperty SelectedItemProperty = PerspexProperty.Register("SelectedItem"); @@ -21,6 +25,16 @@ namespace Perspex.Controls.Primitives { FocusableProperty.OverrideDefaultValue(typeof(SelectingItemsControl), true); + SelectedIndexProperty.Changed.Subscribe(x => + { + var control = x.Sender as SelectingItemsControl; + + if (control != null) + { + control.SelectedItem = control.GetItemAt((int)x.NewValue); + } + }); + SelectedItemProperty.Changed.Subscribe(x => { var control = x.Sender as SelectingItemsControl; @@ -32,6 +46,12 @@ namespace Perspex.Controls.Primitives }); } + public int SelectedIndex + { + get { return this.GetValue(SelectedIndexProperty); } + set { this.SetValue(SelectedIndexProperty, value); } + } + public object SelectedItem { get { return this.GetValue(SelectedItemProperty); } @@ -40,7 +60,13 @@ namespace Perspex.Controls.Primitives protected static int GetIndexOfItem(IEnumerable items, object item) { - if (items != null) + var list = items as IList; + + if (list != null) + { + return list.IndexOf(item); + } + else if (items != null) { int index = 0; @@ -58,11 +84,32 @@ namespace Perspex.Controls.Primitives return -1; } + protected static object GetItemAt(IEnumerable items, int index) + { + var list = items as IList; + + if (list != null) + { + return list[index]; + } + else if (items != null) + { + return items.Cast().ElementAt(index); + } + + return -1; + } + protected int GetIndexOfItem(object item) { return GetIndexOfItem(this.Items, item); } + protected object GetItemAt(int index) + { + return GetItemAt(this.Items, index); + } + protected virtual void MoveSelection(FocusNavigationDirection direction) { var panel = this.Presenter?.Panel as INavigablePanel; @@ -150,6 +197,26 @@ namespace Perspex.Controls.Primitives e.Handled = true; } + private static int CoerceSelectedIndex(PerspexObject o, int value) + { + var control = o as SelectingItemsControl; + + if (control != null) + { + if (value < -1) + { + return -1; + } + else if (value > -1) + { + var count = control.Items.Cast().Count(); + return Math.Min(value, count - 1); + } + } + + return value; + } + private void SelectedItemChanged(object selected) { var containers = this.ItemContainerGenerator.GetAll() @@ -168,6 +235,15 @@ namespace Perspex.Controls.Primitives { item.IsSelected = item == selectedContainer; } + + if (selected == null) + { + this.SelectedIndex = -1; + } + else + { + this.SelectedIndex = GetIndexOfItem(selected); + } } } } diff --git a/Tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj b/Tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj index aeb260dab5..788271cece 100644 --- a/Tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj +++ b/Tests/Perspex.Controls.UnitTests/Perspex.Controls.UnitTests.csproj @@ -92,7 +92,7 @@ - + diff --git a/Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs b/Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs new file mode 100644 index 0000000000..3e9e2a3031 --- /dev/null +++ b/Tests/Perspex.Controls.UnitTests/Primitives/SelectingItemsControlTests.cs @@ -0,0 +1,154 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2014 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Controls.Primitives.UnitTests +{ + using Perspex.Controls.Presenters; + using Perspex.Controls.Primitives; + using Perspex.Input; + using Xunit; + + public class SelectingItemsControlTests + { + [Fact] + public void Item_IsSelected_Should_Initially_Be_False() + { + var items = new[] + { + new Item(), + new Item(), + }; + + var target = new Target + { + Items = items, + }; + + Assert.False(items[0].IsSelected); + Assert.False(items[1].IsSelected); + } + + [Fact] + public void Setting_SelectedItem_Should_Set_Item_IsSelected_True() + { + var items = new[] + { + new Item(), + new Item(), + }; + + var target = new Target + { + Items = items, + }; + + target.Template = this.Template(); + target.ApplyTemplate(); + target.SelectedItem = items[1]; + + Assert.False(items[0].IsSelected); + Assert.True(items[1].IsSelected); + } + + [Fact] + public void Setting_SelectedItem_Should_Set_SelectedIndex() + { + var items = new[] + { + new Item(), + new Item(), + }; + + var target = new Target + { + Items = items, + }; + + target.Template = this.Template(); + target.ApplyTemplate(); + target.SelectedItem = items[1]; + + Assert.Equal(1, target.SelectedIndex); + } + + [Fact] + public void Setting_SelectedIndex_Should_Set_SelectedItem() + { + var items = new[] + { + new Item(), + new Item(), + }; + + var target = new Target + { + Items = items, + }; + + target.Template = this.Template(); + target.ApplyTemplate(); + target.SelectedIndex = 1; + + Assert.Equal(items[1], target.SelectedItem); + } + + [Fact] + public void Setting_SelectedIndex_Should_Coerce() + { + var items = new[] + { + new Item(), + new Item(), + }; + + var target = new Target + { + Items = items, + }; + + target.Template = this.Template(); + target.ApplyTemplate(); + target.SelectedIndex = 2; + + Assert.Equal(1, target.SelectedIndex); + } + + [Fact] + public void PointerPressed_Event_Should_Be_Handled() + { + var target = new Target(); + + var e = new PointerPressEventArgs + { + RoutedEvent = InputElement.PointerPressedEvent + }; + + target.RaiseEvent(e); + + Assert.True(e.Handled); + } + + private ControlTemplate Template() + { + return ControlTemplate.Create(control => + new ItemsPresenter + { + Id = "itemsPresenter", + [~ItemsPresenter.ItemsProperty] = control[~ListBox.ItemsProperty], + [~ItemsPresenter.ItemsPanelProperty] = control[~ListBox.ItemsPanelProperty], + }); + } + + private class Target : SelectingItemsControl + { + } + + private class Item : Control, ISelectable + { + public bool IsSelected { get; set; } + } + } +} diff --git a/Tests/Perspex.Controls.UnitTests/SelectingItemsControlTests.cs b/Tests/Perspex.Controls.UnitTests/SelectingItemsControlTests.cs deleted file mode 100644 index 92e47fd1c1..0000000000 --- a/Tests/Perspex.Controls.UnitTests/SelectingItemsControlTests.cs +++ /dev/null @@ -1,34 +0,0 @@ -// ----------------------------------------------------------------------- -// -// Copyright 2014 MIT Licence. See licence.md for more information. -// -// ----------------------------------------------------------------------- - -namespace Perspex.Controls.UnitTests -{ - using Perspex.Controls.Primitives; - using Perspex.Input; - using Xunit; - - public class SelectingItemsControlTests - { - [Fact] - public void PointerPressed_Event_Should_Be_Handled() - { - var target = new Target(); - - var e = new PointerPressEventArgs - { - RoutedEvent = InputElement.PointerPressedEvent - }; - - target.RaiseEvent(e); - - Assert.True(e.Handled); - } - - private class Target : SelectingItemsControl - { - } - } -}