Skip to content

Commit 89305ac

Browse files
committed
Added the tab view context menu changes upon the folder structure change in the main.
1 parent be156ac commit 89305ac

10 files changed

+405
-85
lines changed

WinUIGallery/Helpers/TabViewHelper.cs

+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
using System.Collections;
2+
using Microsoft.UI.Xaml;
3+
using Microsoft.UI.Xaml.Controls;
4+
using Microsoft.UI.Xaml.Media;
5+
6+
namespace WinUIGallery.Helpers;
7+
8+
public static class TabViewHelper
9+
{
10+
public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
11+
{
12+
contextMenu.Items.Clear();
13+
14+
var item = (TabViewItem)contextMenu.Target;
15+
ListView tabViewListView = null;
16+
TabView tabView = null;
17+
18+
DependencyObject current = item;
19+
20+
while (current != null)
21+
{
22+
DependencyObject parent = VisualTreeHelper.GetParent(current);
23+
24+
if (parent is ListView parentTabViewListView)
25+
{
26+
tabViewListView = parentTabViewListView;
27+
}
28+
else if (parent is TabView parentTabView)
29+
{
30+
tabView = parentTabView;
31+
}
32+
33+
if (tabViewListView != null && tabView != null)
34+
{
35+
break;
36+
}
37+
38+
current = parent;
39+
}
40+
41+
if (tabViewListView == null || tabView == null)
42+
{
43+
return;
44+
}
45+
46+
// First, if there are tabs to the left or to the right of the tab on which this context menu is opening,
47+
// then we'll include menu items to move this tab to the left or to the right.
48+
//
49+
// There are two possible cases for tab views: either they have explicitly set tab items, or they have a data item source set.
50+
// To move a tab left or right with explicitly set tab items, we'll remove and replace the tab item itself.
51+
// To move a tab left or right with a data item source set, we'll instead remove and replace the data item in the source list.
52+
int index = tabViewListView.IndexFromContainer(item);
53+
54+
if (index > 0)
55+
{
56+
MenuFlyoutItem moveLeftItem = new() { Text = "Move tab left" };
57+
moveLeftItem.Click += (s, args) =>
58+
{
59+
if (tabView.TabItemsSource is IList itemsSourceList)
60+
{
61+
var item = itemsSourceList[index];
62+
itemsSourceList.RemoveAt(index);
63+
itemsSourceList.Insert(index - 1, item);
64+
}
65+
else
66+
{
67+
var item = tabView.TabItems[index];
68+
tabView.TabItems.RemoveAt(index);
69+
tabView.TabItems.Insert(index - 1, item);
70+
}
71+
};
72+
contextMenu.Items.Add(moveLeftItem);
73+
}
74+
75+
if (index < tabViewListView.Items.Count - 1)
76+
{
77+
MenuFlyoutItem moveRightItem = new() { Text = "Move tab right" };
78+
moveRightItem.Click += (s, args) =>
79+
{
80+
if (tabView.TabItemsSource is IList itemsSourceList)
81+
{
82+
var item = itemsSourceList[index];
83+
itemsSourceList.RemoveAt(index);
84+
itemsSourceList.Insert(index + 1, item);
85+
}
86+
else
87+
{
88+
var item = tabView.TabItems[index];
89+
tabView.TabItems.RemoveAt(index);
90+
tabView.TabItems.Insert(index + 1, item);
91+
}
92+
};
93+
contextMenu.Items.Add(moveRightItem);
94+
}
95+
96+
// If the context menu ended up with no items at all, then we'll prevent it from being shown.
97+
if (contextMenu.Items.Count == 0)
98+
{
99+
contextMenu.Hide();
100+
}
101+
}
102+
}

WinUIGallery/Helpers/UIHelper.cs

+17
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,21 @@ static public void AnnounceActionForAccessibility(UIElement ue, string annouceme
6363
peer.RaiseNotificationEvent(AutomationNotificationKind.ActionCompleted,
6464
AutomationNotificationProcessing.ImportantMostRecent, annoucement, activityID);
6565
}
66+
67+
public static T GetParent<T>(DependencyObject child) where T : DependencyObject
68+
{
69+
DependencyObject current = child;
70+
71+
while (current != null)
72+
{
73+
if (current is T parent)
74+
{
75+
return parent;
76+
}
77+
78+
current = VisualTreeHelper.GetParent(current);
79+
}
80+
81+
return null;
82+
}
6683
}

WinUIGallery/Helpers/Win32WindowHelper.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ namespace WinUIGallery.Helpers;
66

77
internal class Win32WindowHelper
88
{
9-
private static WinProc newWndProc = null;
10-
private static nint oldWndProc = nint.Zero;
9+
private WinProc newWndProc = null;
10+
private nint oldWndProc = nint.Zero;
1111

1212
private POINT? minWindowSize = null;
1313
private POINT? maxWindowSize = null;

WinUIGallery/Samples/ControlPages/TabViewPage.xaml

+18-13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@
99
xmlns:samplepages="using:WinUIGallery.SamplePages"
1010
mc:Ignorable="d">
1111

12+
<Page.Resources>
13+
<MenuFlyout x:Name="TabViewContextMenu" Opening="TabViewContextMenu_Opening" />
14+
</Page.Resources>
15+
1216
<StackPanel>
1317
<controls:ControlExample CSharpSource="TabView\TabViewBasicSample_cs.txt" HeaderText="A TabView with support for adding, closing, and rearranging tabs">
1418
<controls:ControlExample.Example>
@@ -37,19 +41,19 @@
3741
SelectedIndex="0"
3842
TabCloseRequested="TabView_TabCloseRequested">
3943
<TabView.TabItems>
40-
<TabViewItem Header="Document 0">
44+
<TabViewItem Header="Document 0" ContextFlyout="{x:Bind TabViewContextMenu}">
4145
<TabViewItem.IconSource>
4246
<SymbolIconSource Symbol="Placeholder" />
4347
</TabViewItem.IconSource>
4448
<samplepages:SamplePage1 />
4549
</TabViewItem>
46-
<TabViewItem Header="Document 1">
50+
<TabViewItem Header="Document 1" ContextFlyout="{x:Bind TabViewContextMenu}">
4751
<TabViewItem.IconSource>
4852
<SymbolIconSource Symbol="Placeholder" />
4953
</TabViewItem.IconSource>
5054
<samplepages:SamplePage2 />
5155
</TabViewItem>
52-
<TabViewItem Header="Document 2">
56+
<TabViewItem Header="Document 2" ContextFlyout="{x:Bind TabViewContextMenu}">
5357
<TabViewItem.IconSource>
5458
<SymbolIconSource Symbol="Placeholder" />
5559
</TabViewItem.IconSource>
@@ -101,7 +105,8 @@
101105
<TabViewItem
102106
Content="{x:Bind DataContent}"
103107
Header="{x:Bind DataHeader}"
104-
IconSource="{x:Bind DataIconSource}" />
108+
IconSource="{x:Bind DataIconSource}"
109+
ContextFlyout="{x:Bind TabViewContextMenu}" />
105110
</DataTemplate>
106111
</TabView.TabItemTemplate>
107112
</TabView>
@@ -276,19 +281,19 @@
276281
IsAddTabButtonVisible="False"
277282
SelectedIndex="0">
278283
<TabView.TabItems>
279-
<TabViewItem Header="Home" IsClosable="False">
284+
<TabViewItem Header="Home" IsClosable="False" ContextFlyout="{x:Bind TabViewContextMenu}">
280285
<TabViewItem.IconSource>
281286
<SymbolIconSource Symbol="Home" />
282287
</TabViewItem.IconSource>
283288
<samplepages:SamplePage1 />
284289
</TabViewItem>
285-
<TabViewItem Header="Tab 2 Has Longer Text" IsClosable="False">
290+
<TabViewItem Header="Tab 2 Has Longer Text" IsClosable="False" ContextFlyout="{x:Bind TabViewContextMenu}">
286291
<TabViewItem.IconSource>
287292
<SymbolIconSource Symbol="MusicInfo" />
288293
</TabViewItem.IconSource>
289294
<samplepages:SamplePage2 />
290295
</TabViewItem>
291-
<TabViewItem Header="Third Tab" IsClosable="False">
296+
<TabViewItem Header="Third Tab" IsClosable="False" ContextFlyout="{x:Bind TabViewContextMenu}">
292297
<TabViewItem.IconSource>
293298
<SymbolIconSource Symbol="Placeholder" />
294299
</TabViewItem.IconSource>
@@ -327,19 +332,19 @@
327332
IsAddTabButtonVisible="False"
328333
SelectedIndex="0">
329334
<TabView.TabItems>
330-
<TabViewItem Header="Home">
335+
<TabViewItem Header="Home" ContextFlyout="{x:Bind TabViewContextMenu}">
331336
<TabViewItem.IconSource>
332337
<SymbolIconSource Symbol="Home" />
333338
</TabViewItem.IconSource>
334339
<samplepages:SamplePage1 />
335340
</TabViewItem>
336-
<TabViewItem Header="Tab 2 Has Longer Text">
341+
<TabViewItem Header="Tab 2 Has Longer Text" ContextFlyout="{x:Bind TabViewContextMenu}">
337342
<TabViewItem.IconSource>
338343
<SymbolIconSource Symbol="MusicInfo" />
339344
</TabViewItem.IconSource>
340345
<samplepages:SamplePage2 />
341346
</TabViewItem>
342-
<TabViewItem Header="Third Tab">
347+
<TabViewItem Header="Third Tab" ContextFlyout="{x:Bind TabViewContextMenu}">
343348
<TabViewItem.IconSource>
344349
<SymbolIconSource Symbol="Placeholder" />
345350
</TabViewItem.IconSource>
@@ -383,17 +388,17 @@
383388
SelectedIndex="0"
384389
TabWidthMode="SizeToContent">
385390
<TabView.TabItems>
386-
<TabViewItem Header="CMD Prompt" IsClosable="False">
391+
<TabViewItem Header="CMD Prompt" IsClosable="False" ContextFlyout="{x:Bind TabViewContextMenu}">
387392
<TabViewItem.IconSource>
388393
<BitmapIconSource ShowAsMonochrome="False" UriSource="ms-appx:///Assets/SampleMedia/cmd.png" />
389394
</TabViewItem.IconSource>
390395
</TabViewItem>
391-
<TabViewItem Header="PowerShell" IsClosable="False">
396+
<TabViewItem Header="PowerShell" IsClosable="False" ContextFlyout="{x:Bind TabViewContextMenu}">
392397
<TabViewItem.IconSource>
393398
<BitmapIconSource ShowAsMonochrome="False" UriSource="ms-appx:///Assets/SampleMedia/powershell.png" />
394399
</TabViewItem.IconSource>
395400
</TabViewItem>
396-
<TabViewItem Header="Windows Subsystem for Linux" IsClosable="False">
401+
<TabViewItem Header="Windows Subsystem for Linux" IsClosable="False" ContextFlyout="{x:Bind TabViewContextMenu}">
397402
<TabViewItem.IconSource>
398403
<BitmapIconSource ShowAsMonochrome="False" UriSource="ms-appx:///Assets/SampleMedia/linux.png" />
399404
</TabViewItem.IconSource>

WinUIGallery/Samples/ControlPages/TabViewPage.xaml.cs

+7-1
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ private TabViewItem CreateNewTab(int index)
5353
TabViewItem newItem = new TabViewItem
5454
{
5555
Header = $"Document {index}",
56-
IconSource = new Microsoft.UI.Xaml.Controls.SymbolIconSource() { Symbol = Symbol.Document }
56+
IconSource = new Microsoft.UI.Xaml.Controls.SymbolIconSource() { Symbol = Symbol.Document },
57+
ContextFlyout = TabViewContextMenu
5758
};
5859

5960
// The content of the tab is often a frame that contains a page, though it could be any UIElement.
@@ -251,4 +252,9 @@ private void TabViewWindowingButton_Click(object sender, Microsoft.UI.Xaml.Route
251252

252253
newWindow.Activate();
253254
}
255+
256+
private void TabViewContextMenu_Opening(object sender, object e)
257+
{
258+
TabViewHelper.PopulateTabViewContextMenu((MenuFlyout)sender);
259+
}
254260
}

WinUIGallery/Samples/SamplePages/TabContentSampleControl.xaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<TextBlock Text="{Binding}" Style="{ThemeResource TitleTextBlockStyle}" />
1414
<TextBlock Text="Drag the Tab outside of the window to spawn a new window." Style="{ThemeResource SubtitleTextBlockStyle}" />
1515
<TextBlock Text="Notice that the state of the Tab is maintained in the new window. For example, if you toggle the ToggleSwitch ON, it will remain ON in the new window." Style="{ThemeResource BodyTextBlockStyle}" />
16-
<ToggleSwitch x:Name="ControlToggle" Header="Turn on ProgressRing" Margin="0,8" />
17-
<ProgressRing IsActive="{x:Bind ControlToggle.IsOn, Mode=OneWay}" HorizontalAlignment="Left" />
16+
<ToggleSwitch x:Name="ControlToggle" Header="Turn on ProgressRing" Margin="0,8" IsOn="{x:Bind IsInProgress, Mode=TwoWay}" />
17+
<ProgressRing IsActive="{x:Bind IsInProgress, Mode=OneWay}" HorizontalAlignment="Left" />
1818
</StackPanel>
1919
</UserControl>

WinUIGallery/Samples/SamplePages/TabContentSampleControl.xaml.cs

+10
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
using Microsoft.UI.Xaml;
12
using Microsoft.UI.Xaml.Controls;
23

34
namespace WinUIGallery.SamplePages;
@@ -8,4 +9,13 @@ public TabContentSampleControl()
89
{
910
this.InitializeComponent();
1011
}
12+
public bool IsInProgress
13+
{
14+
get { return (bool)GetValue(IsInProgressProperty); }
15+
set { SetValue(IsInProgressProperty, value); }
16+
}
17+
18+
public static readonly DependencyProperty IsInProgressProperty = DependencyProperty.Register("IsInProgress", typeof(bool), typeof(TabContentSampleControl), new PropertyMetadata(false));
19+
20+
1121
}

WinUIGallery/Samples/SamplePages/TabViewWindowingSamplePage.xaml

+24-10
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,36 @@
99
mc:Ignorable="d">
1010

1111
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
12-
<TabView
13-
x:Name="Tabs"
14-
VerticalAlignment="Stretch"
15-
AddTabButtonClick="Tabs_AddTabButtonClick"
16-
CanTearOutTabs="True"
17-
ExternalTornOutTabsDropped="Tabs_ExternalTornOutTabsDropped"
18-
ExternalTornOutTabsDropping="Tabs_ExternalTornOutTabsDropping"
19-
TabCloseRequested="Tabs_TabCloseRequested"
20-
TabTearOutRequested="Tabs_TabTearOutRequested"
21-
TabTearOutWindowRequested="Tabs_TabTearOutWindowRequested">
12+
<TabView
13+
x:Name="Tabs"
14+
VerticalAlignment="Stretch"
15+
AddTabButtonClick="Tabs_AddTabButtonClick"
16+
TabCloseRequested="Tabs_TabCloseRequested"
17+
CanTearOutTabs="True"
18+
TabTearOutWindowRequested="Tabs_TabTearOutWindowRequested"
19+
TabTearOutRequested="Tabs_TabTearOutRequested"
20+
ExternalTornOutTabsDropping="Tabs_ExternalTornOutTabsDropping"
21+
ExternalTornOutTabsDropped="Tabs_ExternalTornOutTabsDropped"
22+
TabItemsSource="{x:Bind TabItemDataList}">
2223
<TabView.TabStripHeader>
2324
<Grid x:Name="ShellTitleBarInset" Background="Transparent" />
2425
</TabView.TabStripHeader>
2526
<TabView.TabStripFooter>
2627
<Grid x:Name="CustomDragRegion" Background="Transparent" />
2728
</TabView.TabStripFooter>
29+
<TabView.TabItemTemplate>
30+
<DataTemplate x:DataType="local:TabItemData">
31+
<TabViewItem Header="{x:Bind Header}">
32+
<TabViewItem.ContextFlyout>
33+
<MenuFlyout Opening="TabViewContextMenu_Opening" />
34+
</TabViewItem.ContextFlyout>
35+
<TabViewItem.IconSource>
36+
<SymbolIconSource Symbol="Placeholder" />
37+
</TabViewItem.IconSource>
38+
<local:TabContentSampleControl DataContext="{x:Bind Content}" IsInProgress="{x:Bind IsInProgress, Mode=TwoWay}" />
39+
</TabViewItem>
40+
</DataTemplate>
41+
</TabView.TabItemTemplate>
2842
</TabView>
2943
</Grid>
3044
</Page>

0 commit comments

Comments
 (0)