Skip to content

Commit 9e7ab5d

Browse files
authored
Merge pull request #3275 from MartinZikmund/feature/masterdetailsselectedindex
Add MasterDetailsView.SelectedIndex
2 parents 24fede1 + 4d72c58 commit 9e7ab5d

File tree

4 files changed

+154
-7
lines changed

4 files changed

+154
-7
lines changed

Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.Properties.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ namespace Microsoft.Toolkit.Uwp.UI.Controls
1515
/// <seealso cref="Windows.UI.Xaml.Controls.ItemsControl" />
1616
public partial class MasterDetailsView
1717
{
18+
/// <summary>
19+
/// Identifies the SelectedIndex dependency property.
20+
/// </summary>
21+
public static readonly DependencyProperty SelectedIndexProperty =
22+
DependencyProperty.Register(
23+
nameof(SelectedIndex),
24+
typeof(int),
25+
typeof(MasterDetailsView),
26+
new PropertyMetadata(-1, OnSelectedIndexChanged));
27+
1828
/// <summary>
1929
/// Identifies the <see cref="SelectedItem"/> dependency property.
2030
/// </summary>
@@ -163,6 +173,16 @@ public partial class MasterDetailsView
163173
typeof(MasterDetailsView),
164174
new PropertyMetadata(BackButtonBehavior.System, OnBackButtonBehaviorChanged));
165175

176+
/// <summary>
177+
/// Gets or sets the index of the current selection.
178+
/// </summary>
179+
/// <returns>The index of the current selection, or -1 if the selection is empty.</returns>
180+
public int SelectedIndex
181+
{
182+
get { return (int)GetValue(SelectedIndexProperty); }
183+
set { SetValue(SelectedIndexProperty, value); }
184+
}
185+
166186
/// <summary>
167187
/// Gets or sets the selected item.
168188
/// </summary>

Microsoft.Toolkit.Uwp.UI.Controls/MasterDetailsView/MasterDetailsView.cs

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,25 +96,48 @@ protected override void OnApplyTemplate()
9696
}
9797

9898
/// <summary>
99-
/// Fired when the SelectedItem changes.
99+
/// Fired when the SelectedIndex changes.
100100
/// </summary>
101101
/// <param name="d">The sender</param>
102102
/// <param name="e">The event args</param>
103103
/// <remarks>
104104
/// Sets up animations for the DetailsPresenter for animating in/out.
105105
/// </remarks>
106-
private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
106+
private static void OnSelectedIndexChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
107107
{
108108
var view = (MasterDetailsView)d;
109109

110-
view.OnSelectionChanged(new SelectionChangedEventArgs(new List<object> { e.OldValue }, new List<object> { e.NewValue }));
110+
var newValue = (int)e.NewValue < 0 ? null : view.Items[(int)e.NewValue];
111+
var oldValue = e.OldValue == null ? null : view.Items.ElementAtOrDefault((int)e.OldValue);
111112

112-
view.UpdateView(true);
113+
// check if selection actually changed
114+
if (view.SelectedItem != newValue)
115+
{
116+
// sync SelectedItem
117+
view.SetValue(SelectedItemProperty, newValue);
118+
view.UpdateSelection(oldValue, newValue);
119+
}
120+
}
113121

114-
// If there is no selection, do not remove the DetailsPresenter content but let it animate out.
115-
if (view.SelectedItem != null)
122+
/// <summary>
123+
/// Fired when the SelectedItem changes.
124+
/// </summary>
125+
/// <param name="d">The sender</param>
126+
/// <param name="e">The event args</param>
127+
/// <remarks>
128+
/// Sets up animations for the DetailsPresenter for animating in/out.
129+
/// </remarks>
130+
private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
131+
{
132+
var view = (MasterDetailsView)d;
133+
var index = e.NewValue == null ? -1 : view.Items.IndexOf(e.NewValue);
134+
135+
// check if selection actually changed
136+
if (view.SelectedIndex != index)
116137
{
117-
view.SetDetailsContent();
138+
// sync SelectedIndex
139+
view.SetValue(SelectedIndexProperty, index);
140+
view.UpdateSelection(e.OldValue, e.NewValue);
118141
}
119142
}
120143

@@ -228,6 +251,24 @@ private void OnInlineBackButtonClicked(object sender, RoutedEventArgs e)
228251
SelectedItem = null;
229252
}
230253

254+
/// <summary>
255+
/// Raises SelectionChanged event and updates view.
256+
/// </summary>
257+
/// <param name="oldSelection">Old selection.</param>
258+
/// <param name="newSelection">New selection.</param>
259+
private void UpdateSelection(object oldSelection, object newSelection)
260+
{
261+
OnSelectionChanged(new SelectionChangedEventArgs(new List<object> { oldSelection }, new List<object> { newSelection }));
262+
263+
UpdateView(true);
264+
265+
// If there is no selection, do not remove the DetailsPresenter content but let it animate out.
266+
if (SelectedItem != null)
267+
{
268+
SetDetailsContent();
269+
}
270+
}
271+
231272
private void HandleStateChanges()
232273
{
233274
UpdateView(true);
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using Microsoft.Toolkit.Uwp.UI.Controls;
6+
using Microsoft.VisualStudio.TestTools.UnitTesting;
7+
using Microsoft.VisualStudio.TestTools.UnitTesting.AppContainer;
8+
using System;
9+
using System.Collections.Generic;
10+
using System.Linq;
11+
using System.Text;
12+
using System.Threading.Tasks;
13+
14+
namespace UnitTests.UI.Controls
15+
{
16+
[TestClass]
17+
public class Test_MasterDetailsView
18+
{
19+
[TestCategory("MasterDetailsView")]
20+
[UITestMethod]
21+
public void Test_SelectedIndex_Default()
22+
{
23+
var items = Enumerable.Range(1, 10).ToArray();
24+
var masterDetailsView = new MasterDetailsView();
25+
masterDetailsView.ItemsSource = items;
26+
Assert.AreEqual(-1, masterDetailsView.SelectedIndex);
27+
}
28+
29+
[TestCategory("MasterDetailsView")]
30+
[UITestMethod]
31+
public void Test_SelectedItem_Default()
32+
{
33+
var items = Enumerable.Range(1, 10).ToArray();
34+
var masterDetailsView = new MasterDetailsView();
35+
masterDetailsView.ItemsSource = items;
36+
Assert.IsNull(masterDetailsView.SelectedItem);
37+
}
38+
39+
[TestCategory("MasterDetailsView")]
40+
[UITestMethod]
41+
public void Test_SelectedIndex_Syncs_SelectedItem()
42+
{
43+
var items = Enumerable.Range(1, 10).ToArray();
44+
var masterDetailsView = new MasterDetailsView();
45+
masterDetailsView.ItemsSource = items;
46+
masterDetailsView.SelectedIndex = 6;
47+
Assert.AreEqual(items[6], masterDetailsView.SelectedItem);
48+
}
49+
50+
[TestCategory("MasterDetailsView")]
51+
[UITestMethod]
52+
public void Test_UnselectUsingIndex()
53+
{
54+
var items = Enumerable.Range(1, 10).ToArray();
55+
var masterDetailsView = new MasterDetailsView();
56+
masterDetailsView.ItemsSource = items;
57+
masterDetailsView.SelectedIndex = 5;
58+
masterDetailsView.SelectedIndex = -1;
59+
Assert.IsNull(masterDetailsView.SelectedItem);
60+
}
61+
62+
[TestCategory("MasterDetailsView")]
63+
[UITestMethod]
64+
public void Test_UnselectUsingItem()
65+
{
66+
var items = Enumerable.Range(1, 10).ToArray();
67+
var masterDetailsView = new MasterDetailsView();
68+
masterDetailsView.ItemsSource = items;
69+
masterDetailsView.SelectedItem = items[5];
70+
masterDetailsView.SelectedItem = null;
71+
Assert.AreEqual(-1, masterDetailsView.SelectedIndex);
72+
}
73+
74+
[TestCategory("MasterDetailsView")]
75+
[UITestMethod]
76+
public void Test_SelectedItem_Syncs_SelectedIndex()
77+
{
78+
var items = Enumerable.Range(0, 10).ToArray();
79+
var masterDetailsView = new MasterDetailsView();
80+
masterDetailsView.ItemsSource = items;
81+
masterDetailsView.SelectedItem = items[3];
82+
Assert.AreEqual(3, masterDetailsView.SelectedIndex);
83+
}
84+
}
85+
}

UnitTests/UnitTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175
<Compile Include="Collections\ReadOnlyObservableGroupTests.cs" />
176176
<Compile Include="Properties\AssemblyInfo.cs" />
177177
<Compile Include="Helpers\Test_WeakEventListener.cs" />
178+
<Compile Include="UI\Controls\Test_MasterDetailsView.cs" />
178179
<Compile Include="UI\Controls\Test_UniformGrid_AutoLayout.cs" />
179180
<Compile Include="UI\Controls\Test_UniformGrid_RowColDefinitions.cs" />
180181
<Compile Include="UI\Controls\Test_UniformGrid_FreeSpots.cs" />

0 commit comments

Comments
 (0)