Skip to content

Commit 91f604e

Browse files
author
Kai Guo
authored
TreeView selection APIs (#243)
* Add IsContentMode on TreeViewList * Add SelectedNode * Add TreeViewSelectedNodeTest * Add SelectedItem * Refactor * Add SelectedItem test * Fix tests * Add SelectedItems * Update ViewModel * Update tests * Remove unused code * Add ItemFromNode * Add comments * Skip tests on lower os versions * Update null checks * Update tests * Cleanups * Update ItemFromNode * Ignore m_originalNode when updating selection * Update NodeFromItem * Update ViewModel reference to be weak ref * Add GetViewModel * Update weak refs * Set the new apis to preview * Fix #386 * Fix NodeFromItem * Fix test * Cleanups * Fix single selection * Cleanups * More cleanups
1 parent 644f445 commit 91f604e

22 files changed

+601
-312
lines changed

dev/TreeView/InteractionTests/TreeViewTests.cs

Lines changed: 150 additions & 70 deletions
Large diffs are not rendered by default.

dev/TreeView/TestUI/ExplorerItem.cs

Lines changed: 0 additions & 73 deletions
This file was deleted.

dev/TreeView/TestUI/ExplorerItemTemplateSelector.cs

Lines changed: 0 additions & 23 deletions
This file was deleted.

dev/TreeView/TestUI/TreeViewPage.xaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
<Button x:Name="ItemTemplateSelectorTestPage" AutomationProperties.Name="ItemTemplateSelectorTestPage" Content="ItemTemplateSelectorTestPage" HorizontalAlignment="Stretch" Margin="1" Click="ItemTemplateSelectorTestPage_Click"/>
6363
<Button x:Name="AddNodeWithEmpyUnrealizedChildren" AutomationProperties.Name="AddNodeWithEmpyUnrealizedChildren" Content="AddNodeWithEmpyUnrealizedChildren" HorizontalAlignment="Stretch" Margin="1" Click="AddNodeWithEmpyUnrealizedChildren_Click"/>
6464
<Button x:Name="GetMultiSelectCheckBoxStates" AutomationProperties.Name="GetMultiSelectCheckBoxStates" Content="GetMultiSelectCheckBoxStates" HorizontalAlignment="Stretch" Margin="1" Click="GetMultiSelectCheckBoxStates_Click"/>
65+
<Button x:Name="ToggleRoot0Selection" AutomationProperties.Name="ToggleRoot0Selection" Content="ToggleRoot0Selection" HorizontalAlignment="Stretch" Margin="1" Click="ToggleRoot0Selection_Click"/>
6566
<Button x:Name="ToggleSelectedNodes" AutomationProperties.Name="ToggleSelectedNodes" Content="ToggleSelectedNodes" HorizontalAlignment="Stretch" Margin="1" Click="ToggleSelectedNodes_Click"/>
6667
<Button x:Name="AddInheritedTreeViewNode" AutomationProperties.Name="AddInheritedTreeViewNode" Content="AddInheritedTreeViewNode" HorizontalAlignment="Stretch" Margin="1" Click="AddInheritedTreeViewNode_Click"/>
6768
<Button x:Name="ClearNodes" AutomationProperties.Name="ClearNodes" Content="ClearNodes" HorizontalAlignment="Stretch" Margin="1" Click="ClearNodes_Click"/>
@@ -110,7 +111,6 @@
110111
ItemsSource="{x:Bind Children}"
111112
Content="{x:Bind Content}"
112113
IsExpanded="{x:Bind IsExpanded, Mode=TwoWay}"
113-
IsSelected="{x:Bind IsSelected, Mode=TwoWay}"
114114
HasUnrealizedChildren="{x:Bind HasUnrealizedChildren, Mode=TwoWay}"/>
115115
</DataTemplate>
116116
</muxcontrols:TreeView.ItemTemplate>

dev/TreeView/TestUI/TreeViewPage.xaml.cs

Lines changed: 63 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -80,28 +80,41 @@ protected override void OnNavigatedFrom(NavigationEventArgs e)
8080
base.OnNavigatedFrom(e);
8181
}
8282

83-
private String GetSelection(TreeView tree)
83+
private string GetSelection(TreeView tree)
8484
{
85-
String result="";
86-
if (TestTreeView.SelectionMode == TreeViewSelectionMode.Single)
85+
int count = tree.SelectedNodes.Count;
86+
87+
if (count != tree.SelectedItems.Count)
8788
{
88-
var listControl = FindVisualChildByName(tree, "ListControl") as TreeViewList;
89-
if (IsInContentMode())
90-
{
91-
result = "ItemSelected:" + ((TreeViewItemSource)listControl.SelectedItem).Content;
92-
}
93-
else
89+
return "SelectedNodes.Count != SelectedItems.Count";
90+
}
91+
92+
List<string> result = new List<string>();
93+
for (int i = 0; i < count; i++)
94+
{
95+
// Make sure selectedNodes and SelectedItems are in sync
96+
var node = tree.SelectedNodes[i];
97+
var item = IsInContentMode() ? node.Content : node;
98+
if (item != tree.SelectedItems[i])
9499
{
95-
result = "ItemSelected:" + ((TreeViewNode)listControl.SelectedItem).Content.ToString();
100+
return "$SelectedNodes[{i}] != SelectedItems[{i}]";
96101
}
102+
103+
result.Add(GetNodeContent(node));
97104
}
98-
else if (TestTreeView.SelectionMode == TreeViewSelectionMode.Multiple)
105+
106+
result.Sort();
107+
108+
// Verify SelectedItem and SelectedNode for single selection
109+
if(tree.SelectionMode == TreeViewSelectionMode.Single && result.Count > 0)
99110
{
100-
var items = tree.SelectedNodes;
101-
int count = items.Count;
102-
result = "Num. Selected: " + count;
111+
if(tree.SelectedItem != tree.SelectedItems[0] || tree.SelectedNode != tree.SelectedNodes[0])
112+
{
113+
return "SelectedItem!=SelectedItems[0] || SelectedNode!=SelectedNodes[0]";
114+
}
103115
}
104-
return result;
116+
117+
return result.Count > 0 ? "Selected: " + string.Join(", ", result) : "Nothing selected";
105118
}
106119

107120
private void GetSelected_Click(object sender, RoutedEventArgs e)
@@ -817,19 +830,39 @@ private void GetMultiSelectCheckBoxStates_Click(object sender, RoutedEventArgs e
817830

818831
private void ToggleSelectedNodes_Click(object sender, RoutedEventArgs e)
819832
{
820-
TestTreeView.SelectionMode = TreeViewSelectionMode.Multiple;
821-
var root0 = TestTreeView.RootNodes[0].Children[0];
822-
var root2 = TestTreeView.RootNodes[0].Children[2];
823-
var selectedNodes = TestTreeView.SelectedNodes;
824-
if (selectedNodes.Contains(root0))
833+
if (IsInContentMode())
825834
{
826-
selectedNodes.Remove(root0);
827-
selectedNodes.Remove(root2);
835+
ContentModeTestTreeView.SelectionMode = TreeViewSelectionMode.Multiple;
836+
var item0 = TestTreeViewItemsSource[0].Children[0];
837+
var item2 = TestTreeViewItemsSource[0].Children[2];
838+
var selectedItems = ContentModeTestTreeView.SelectedItems;
839+
if (selectedItems.Contains(item0))
840+
{
841+
selectedItems.Remove(item0);
842+
selectedItems.Remove(item2);
843+
}
844+
else
845+
{
846+
selectedItems.Add(item0);
847+
selectedItems.Add(item2);
848+
}
828849
}
829850
else
830851
{
831-
selectedNodes.Add(root0);
832-
selectedNodes.Add(root2);
852+
TestTreeView.SelectionMode = TreeViewSelectionMode.Multiple;
853+
var node0 = TestTreeView.RootNodes[0].Children[0];
854+
var node2 = TestTreeView.RootNodes[0].Children[2];
855+
var selectedNodes = TestTreeView.SelectedNodes;
856+
if (selectedNodes.Contains(node0))
857+
{
858+
selectedNodes.Remove(node0);
859+
selectedNodes.Remove(node2);
860+
}
861+
else
862+
{
863+
selectedNodes.Add(node0);
864+
selectedNodes.Add(node2);
865+
}
833866
}
834867
}
835868

@@ -901,6 +934,12 @@ private void TreeViewLateDataInitTestPage_Click(object sender, RoutedEventArgs e
901934
Frame.NavigateWithoutAnimation(typeof(TreeViewLateDataInitTest));
902935
}
903936

937+
private void ToggleRoot0Selection_Click(object sender, RoutedEventArgs e)
938+
{
939+
TestTreeView.SelectedNode = TestTreeView.SelectedNode == null ? TestTreeView.RootNodes[0].Children[0] : null;
940+
ContentModeTestTreeView.SelectedItem = ContentModeTestTreeView.SelectedItem==null ? TestTreeViewItemsSource[0].Children[0] : null;
941+
}
942+
904943
private void TreeViewNodeInMarkupTestPage_Click(object sender, RoutedEventArgs e)
905944
{
906945
Frame.NavigateWithoutAnimation(typeof(TreeViewNodeInMarkupTestPage));

dev/TreeView/TestUI/TreeView_TestUI.projitems

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,6 @@
1010
<Import_RootNamespace>TreeView_TestUI</Import_RootNamespace>
1111
</PropertyGroup>
1212
<ItemGroup>
13-
<Compile Include="$(MSBuildThisFileDirectory)ExplorerItem.cs" />
14-
<Compile Include="$(MSBuildThisFileDirectory)ExplorerItemTemplateSelector.cs" />
1513
<Compile Include="$(MSBuildThisFileDirectory)TreeViewItemTemplateSelectorTestPage.xaml.cs">
1614
<DependentUpon>TreeViewItemTemplateSelectorTestPage.xaml</DependentUpon>
1715
</Compile>

dev/TreeView/TreeView.cpp

Lines changed: 56 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,44 @@ TreeViewList* TreeView::ListControl()
3838

3939
winrt::IInspectable TreeView::ItemFromContainer(winrt::DependencyObject const& container)
4040
{
41-
return ListControl()->ItemFromContainer(container);
41+
return ListControl() ? ListControl()->ItemFromContainer(container) : nullptr;
4242
}
4343

4444
winrt::DependencyObject TreeView::ContainerFromItem(winrt::IInspectable const& item)
4545
{
46-
return ListControl()->ContainerFromItem(item);
46+
return ListControl() ? ListControl()->ContainerFromItem(item) : nullptr;
4747
}
4848

4949
winrt::TreeViewNode TreeView::NodeFromContainer(winrt::DependencyObject const& container)
5050
{
51-
return ListControl()->NodeFromContainer(container);
51+
return ListControl() ? ListControl()->NodeFromContainer(container) : nullptr;
5252
}
5353

5454
winrt::DependencyObject TreeView::ContainerFromNode(winrt::TreeViewNode const& node)
5555
{
56-
return ListControl()->ContainerFromNode(node);
56+
return ListControl() ? ListControl()->ContainerFromNode(node) : nullptr;
5757
}
5858

59+
void TreeView::SelectedNode(winrt::TreeViewNode const& node)
60+
{
61+
auto selectedNodes = SelectedNodes();
62+
if (selectedNodes.Size() > 0)
63+
{
64+
selectedNodes.Clear();
65+
}
66+
if (node)
67+
{
68+
selectedNodes.Append(node);
69+
}
70+
}
71+
72+
winrt::TreeViewNode TreeView::SelectedNode()
73+
{
74+
auto nodes = SelectedNodes();
75+
return nodes.Size() > 0 ? nodes.GetAt(0) : nullptr;
76+
}
77+
78+
5979
winrt::IVector<winrt::TreeViewNode> TreeView::SelectedNodes()
6080
{
6181
if (auto listControl = ListControl())
@@ -70,6 +90,38 @@ winrt::IVector<winrt::TreeViewNode> TreeView::SelectedNodes()
7090
return m_pendingSelectedNodes.get();
7191
}
7292

93+
void TreeView::SelectedItem(winrt::IInspectable const& item)
94+
{
95+
auto selectedItems = SelectedItems();
96+
if (selectedItems.Size() > 0)
97+
{
98+
selectedItems.Clear();
99+
}
100+
if (item)
101+
{
102+
selectedItems.Append(item);
103+
}
104+
}
105+
106+
winrt::IInspectable TreeView::SelectedItem()
107+
{
108+
auto items = SelectedItems();
109+
return items.Size() > 0 ? items.GetAt(0) : nullptr;
110+
}
111+
112+
winrt::IVector<winrt::IInspectable> TreeView::SelectedItems()
113+
{
114+
if (auto listControl = ListControl())
115+
{
116+
if (auto viewModel = listControl->ListViewModel())
117+
{
118+
return viewModel->GetSelectedItems();
119+
}
120+
}
121+
122+
return nullptr;
123+
}
124+
73125
void TreeView::Expand(winrt::TreeViewNode const& value)
74126
{
75127
auto vm = ListControl()->ListViewModel();

dev/TreeView/TreeView.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,14 @@ class TreeView :
2727
winrt::TreeViewNode NodeFromContainer(winrt::DependencyObject const& container);
2828
winrt::DependencyObject ContainerFromNode(winrt::TreeViewNode const& node);
2929

30+
void SelectedNode(winrt::TreeViewNode const& node);
31+
winrt::TreeViewNode SelectedNode();
3032
winrt::IVector<winrt::TreeViewNode> SelectedNodes();
33+
34+
void SelectedItem(winrt::IInspectable const& item);
35+
winrt::IInspectable SelectedItem();
36+
winrt::IVector<winrt::IInspectable> SelectedItems();
37+
3138
void Expand(winrt::TreeViewNode const& value);
3239
void Collapse(winrt::TreeViewNode const& value);
3340
void SelectAll();
@@ -68,4 +75,4 @@ class TreeView :
6875
winrt::ListViewBase::ContainerContentChanging_revoker m_containerContentChangingRevoker{};
6976
winrt::ListViewBase::DragItemsStarting_revoker m_dragItemsStartingRevoker{};
7077
winrt::ListViewBase::DragItemsCompleted_revoker m_dragItemsCompletedRevoker{};
71-
};
78+
};

dev/TreeView/TreeView.idl

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,13 @@ unsealed runtimeclass TreeView : Windows.UI.Xaml.Controls.Control
152152
static Windows.UI.Xaml.DependencyProperty ItemContainerTransitionsProperty{ get; };
153153
static Windows.UI.Xaml.DependencyProperty ItemsSourceProperty{ get; };
154154
}
155+
156+
[WUXC_VERSION_PREVIEW]
157+
{
158+
TreeViewNode SelectedNode{ get; set; };
159+
Object SelectedItem{ get; set; };
160+
Windows.Foundation.Collections.IVector<Object> SelectedItems{ get; };
161+
}
155162
}
156163

157164
[WUXC_VERSION_RS4]

dev/TreeView/TreeView.vcxitems

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,10 +77,6 @@
7777
<Version>RS2</Version>
7878
<Type>ThemeResources</Type>
7979
</Page>
80-
<Page Include="$(MSBuildThisFileDirectory)TreeView_rs5_themeresources.xaml">
81-
<Version>RS5</Version>
82-
<Type>ThemeResources</Type>
83-
</Page>
8480
</ItemGroup>
8581
<ItemGroup>
8682
<PRIResource Include="$(MSBuildThisFileDirectory)Strings\en-US\Resources.resw" />

0 commit comments

Comments
 (0)