Repository: microsoft/WinUI-Gallery
Pull request #1821: Added the context menu for the tab view for left and right actions.
Author: login: sabareesanms
Created: 2025-03-27T07:24:40Z | Merged: 2025-03-31T09:22:45Z

**Bug** [52757718](https://dev.azure.com/microsoft/OS/_workitems/edit/52757718) Lack of Alternative Single Pointer Method for Tab Movement in TabView Screen.

**Fix** - Adding context menu for the TabView example in the WinUI Gallery which allows the tabs to be moved left and right with single click in addition to the dragging method.

**Testing** - Tested in the WinUI Gallery app. 

**Screenshots** 

![Screenshot 2025-03-27 123727](https://github.com/user-attachments/assets/4fa44340-7348-4e2a-b576-c21d0fef1cc6)

**Changes** 

1. **WinUIGallery/Helpers/TabViewHelper.cs** - Added a function PopulateTabViewContextMenu(MenuFlyout contextMenu) 
- Gets the parent tab view and tab view item of the context menu.
- Add left move menu if index > 0 with its action (Adds except 1st item)
- Add right move menu if index < count -1   (Adds except last item)
- Closes the menu if the context menu is empty (To avoid empty context menu showing). 

2. **WinUIGallery/Samples/ControlPages/TabViewPage.xaml**
 - Defines the context menu **TabViewContextMenu** in page resource for reusability
 - Adds the context menu to all tabviewitem in the example page. 

3. **WinUIGallery/Samples/ControlPages/TabViewPage.xaml.cs**
 - Added the event handler for the context menu opening event to populate the context menu with the tab view helper function





Diff:
diff --git a/WinUIGallery/Helpers/TabViewHelper.cs b/WinUIGallery/Helpers/TabViewHelper.cs
new file mode 100644
index 000000000..7ab110cec
--- /dev/null
+++ b/WinUIGallery/Helpers/TabViewHelper.cs
@@ -0,0 +1,100 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout menuFlyout)
+    {
+        menuFlyout.Items.Clear();
+
+        var item = (TabViewItem)menuFlyout.Target;
+        if(item == null)
+        {
+            return;
+        }
+        ListView tabViewListView = null;
+        TabView tabView = null;
+
+        DependencyObject current = item;
+
+        while (current != null)
+        {
+            DependencyObject parent = VisualTreeHelper.GetParent(current);
+
+            if (parent is ListView parentTabViewListView)
+            {
+                tabViewListView = parentTabViewListView;
+            }
+            else if (parent is TabView parentTabView)
+            {
+                tabView = parentTabView;
+            }
+
+            if (tabViewListView != null && tabView != null)
+            {
+                break;
+            }
+
+            current = parent;
+        }
+
+        if (tabViewListView == null || tabView == null)
+        {
+            return;
+        }
+
+        // First, if there are tabs to the left or to the right of the tab on which this context menu is opening,
+        // then we'll include menu items to move this tab to the left or to the right.
+        //
+        // There are two possible cases for tab views: either they have explicitly set tab items, or they have a data item source set.
+        // To move a tab left or right with explicitly set tab items, we'll remove and replace the tab item itself.
+        // 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.
+        int index = tabViewListView.IndexFromContainer(item);
+
+        if (index > 0)
+        {
+            MenuFlyoutItem moveLeftItem = new() { Text = "Move tab left" };
+            moveLeftItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
+                    itemsSourceList.RemoveAt(index);
+                    itemsSourceList.Insert(index - 1, item);
+                }
+                else
+                {
+                    var item = tabView.TabItems[index];
+                    tabView.TabItems.RemoveAt(index);
+                    tabView.TabItems.Insert(index - 1, item);
+                }
+            };
+            menuFlyout.Items.Add(moveLeftItem);
+        }
+
+        if (index < tabViewListView.Items.Count - 1)
+        {
+            MenuFlyoutItem moveRightItem = new() { Text = "Move tab right" };
+            moveRightItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
+                    itemsSourceList.RemoveAt(index);
+                    itemsSourceList.Insert(index + 1, item);
+                }
+                else
+                {
+                    var item = tabView.TabItems[index];
+                    tabView.TabItems.RemoveAt(index);
+                    tabView.TabItems.Insert(index + 1, item);
+                }
+            };
+            menuFlyout.Items.Add(moveRightItem);
+        }
+    }
+}
diff --git a/WinUIGallery/Samples/ControlPages/TabViewPage.xaml b/WinUIGallery/Samples/ControlPages/TabViewPage.xaml
index 2fa0d0cb2..ce0914485 100644
--- a/WinUIGallery/Samples/ControlPages/TabViewPage.xaml
+++ b/WinUIGallery/Samples/ControlPages/TabViewPage.xaml
@@ -8,6 +8,9 @@
     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
     xmlns:samplepages="using:WinUIGallery.SamplePages"
     mc:Ignorable="d">
+    <Page.Resources>
+        <MenuFlyout x:Name="TabViewContextMenu" Opening="TabViewContextMenu_Opening" />
+    </Page.Resources>
 
     <StackPanel>
         <controls:ControlExample CSharpSource="TabView\TabViewBasicSample_cs.txt" HeaderText="A TabView with support for adding, closing, and rearranging tabs">
@@ -37,19 +40,19 @@
                     SelectedIndex="0"
                     TabCloseRequested="TabView_TabCloseRequested">
                     <TabView.TabItems>
-                        <TabViewItem Header="Document 0">
+                        <TabViewItem Header="Document 0" ContextFlyout="{x:Bind TabViewContextMenu}">
                             <TabViewItem.IconSource>
                                 <SymbolIconSource Symbol="Placeholder" />
                             </TabViewItem.IconSource>
                             <samplepages:SamplePage1 />
                         </TabViewItem>
-                        <TabViewItem Header="Document 1">
+                        <TabViewItem Header="Document 1" ContextFlyout="{x:Bind TabViewContextMenu}">
                             <TabViewItem.IconSource>
                                 <SymbolIconSource Symbol="Placeholder" />
                             </TabViewItem.IconSource>
                             <samplepages:SamplePage2 />
                         </TabViewItem>
-                        <TabViewItem Header="Document 2">
+                        <TabViewItem Header="Document 2" ContextFlyout="{x:Bind TabViewContextMenu}">
                             <TabViewItem.IconSource>
                                 <SymbolIconSource Symbol="Placeholder" />
                             </TabViewItem.IconSource>
@@ -279,19 +282,19 @@
                     SelectedIndex="0"
                     TabWidthMode="SizeToContent">
                     <TabView.TabItems>
-                        <TabViewItem Header="Home" IsClosable="False">
+                        <TabViewItem Header="Home" IsClosable="False" ContextFlyout="{x:Bind TabViewContextMenu}">
                             <TabViewItem.IconSource>
                                 <SymbolIconSource Symbol="Home" />
                             </TabViewItem.IconSource>
                             <samplepages:SamplePage1 />
                         </TabViewItem>
-                        <TabViewItem Header="Tab 2 Has Longer Text" IsClosable="False">
+                        <TabViewItem Header="Tab 2 Has Longer Text" IsClosable="False" ContextFlyout="{x:Bind TabViewContextMenu}">
                             <TabViewItem.IconSource>
                                 <SymbolIconSource Symbol="MusicInfo" />
                             </TabViewItem.IconSource>
                             <samplepages:SamplePage2 />
                         </TabViewItem>
-                        <TabViewItem Header="Third Tab" IsClosable="False">
+                        <TabViewItem Header="Third Tab" IsClosable="False" ContextFlyout="{x:Bind TabViewContextMenu}">
                             <TabViewItem.IconSource>
                                 <SymbolIconSource Symbol="Placeholder" />
                             </TabViewItem.IconSource>
@@ -330,21 +333,21 @@
                     IsAddTabButtonVisible="False"
                     SelectedIndex="0">
                     <TabView.TabItems>
-                        <TabViewItem Header="Home">
+                        <TabViewItem Header="Home" ContextFlyout="{x:Bind TabViewContextMenu}">
                             <TabViewItem.IconSource>
                                 <SymbolIconSource Symbol="Home" />
                             </TabViewItem.IconSource>
                             <samplepages:SamplePage1 />
                         </TabViewItem>
-                        <TabViewItem Header="Tab 2 Has Longer Text">
+                        <TabViewItem Header="Tab 2 Has Longer Text" ContextFlyout="{x:Bind TabViewContextMenu}">
                             <TabViewItem.IconSource>
                                 <SymbolIconSource Symbol="MusicInfo" />
                             </TabViewItem.IconSource>
                             <samplepages:SamplePage2 />
                         </TabViewItem>
-                        <TabViewItem Header="Third Tab">
+                        <TabViewItem Header="Third Tab" ContextFlyout="{x:Bind TabViewContextMenu}">
                             <TabViewItem.IconSource>
-                                <SymbolIconSource Symbol="Placeholder" />
+                                <SymbolIconSource Symbol="Placeholder"/>
                             </TabViewItem.IconSource>
                             <samplepages:SamplePage3 />
                         </TabViewItem>
@@ -387,17 +390,17 @@
                         SelectedIndex="0"
                         TabWidthMode="SizeToContent">
                         <TabView.TabItems>
-                            <TabViewItem Header="CMD Prompt" IsClosable="False">
+                            <TabViewItem Header="CMD Prompt" IsClosable="False" ContextFlyout="{x:Bind TabViewContextMenu}">
                                 <TabViewItem.IconSource>
                                     <BitmapIconSource ShowAsMonochrome="False" UriSource="ms-appx:///Assets/SampleMedia/cmd.png" />
                                 </TabViewItem.IconSource>
                             </TabViewItem>
-                            <TabViewItem Header="PowerShell" IsClosable="False">
+                            <TabViewItem Header="PowerShell" IsClosable="False" ContextFlyout="{x:Bind TabViewContextMenu}">
                                 <TabViewItem.IconSource>
                                     <BitmapIconSource ShowAsMonochrome="False" UriSource="ms-appx:///Assets/SampleMedia/powershell.png" />
                                 </TabViewItem.IconSource>
                             </TabViewItem>
-                            <TabViewItem Header="Windows Subsystem for Linux" IsClosable="False">
+                            <TabViewItem Header="Windows Subsystem for Linux" IsClosable="False" ContextFlyout="{x:Bind TabViewContextMenu}">
                                 <TabViewItem.IconSource>
                                     <BitmapIconSource ShowAsMonochrome="False" UriSource="ms-appx:///Assets/SampleMedia/linux.png" />
                                 </TabViewItem.IconSource>
diff --git a/WinUIGallery/Samples/ControlPages/TabViewPage.xaml.cs b/WinUIGallery/Samples/ControlPages/TabViewPage.xaml.cs
index be8057147..e17e8f533 100644
--- a/WinUIGallery/Samples/ControlPages/TabViewPage.xaml.cs
+++ b/WinUIGallery/Samples/ControlPages/TabViewPage.xaml.cs
@@ -60,7 +60,8 @@ private TabViewItem CreateNewTab(int index)
         TabViewItem newItem = new TabViewItem
         {
             Header = $"Document {index}",
-            IconSource = new Microsoft.UI.Xaml.Controls.SymbolIconSource() { Symbol = Symbol.Document }
+            IconSource = new Microsoft.UI.Xaml.Controls.SymbolIconSource() { Symbol = Symbol.Document },
+            ContextFlyout = TabViewContextMenu
         };
 
         // The content of the tab is often a frame that contains a page, though it could be any UIElement.
@@ -258,4 +259,15 @@ private void TabViewWindowingButton_Click(object sender, Microsoft.UI.Xaml.Route
 
         newWindow.Activate();
     }
+
+    private void TabViewContextMenu_Opening(object sender, object e)
+    {
+        var menuFlyout = (MenuFlyout)sender; 
+        TabViewHelper.PopulateTabViewContextMenu(menuFlyout);
+        // If the context menu ended up with no items at all, then we'll prevent it from being shown.
+        if (menuFlyout.Items.Count == 0)
+        {
+            menuFlyout.Hide();
+        }
+    }
 }


Reviews:
user: login: godlytalias
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T07:45:05Z
user: login: godlytalias
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-27T08:04:20Z
user: login: Hemantxk
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-27T08:13:58Z
user: login: Hemantxk
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-27T08:15:17Z
user: login: Hemantxk
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-27T08:16:23Z
user: login: Hemantxk
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-27T08:17:05Z
user: login: Hemantxk
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-27T08:17:33Z
user: login: sabareesanms
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T09:59:13Z
user: login: sabareesanms
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T10:00:56Z
user: login: sabareesanms
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T10:20:38Z
user: login: sabareesanms
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T10:20:48Z
user: login: sabareesanms
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T10:21:03Z
user: login: sabareesanms
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-28T10:21:20Z
user: login: Hemantxk
state: APPROVED
author_association: NONE
submitted_at: 2025-03-28T10:28:29Z
user: login: Saharsh979
state: APPROVED
author_association: NONE
submitted_at: 2025-03-31T09:09:51Z

Review comments:
diff_hunk: @@ -0,0 +1,102 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
+    {
+        contextMenu.Items.Clear();
+
+        var item = (TabViewItem)contextMenu.Target;
+        ListView tabViewListView = null;
+        TabView tabView = null;
+
+        DependencyObject current = item;
+
+        while (current != null)
+        {
+            DependencyObject parent = VisualTreeHelper.GetParent(current);
+
+            if (parent is ListView parentTabViewListView)
+            {
+                tabViewListView = parentTabViewListView;
+            }
+            else if (parent is TabView parentTabView)
+            {
+                tabView = parentTabView;
+            }
+
+            if (tabViewListView != null && tabView != null)
+            {
+                break;
+            }
+
+            current = parent;
+        }
+
+        if (tabViewListView == null || tabView == null)
+        {
+            return;
+        }
+
+        // First, if there are tabs to the left or to the right of the tab on which this context menu is opening,
+        // then we'll include menu items to move this tab to the left or to the right.
+        //
+        // There are two possible cases for tab views: either they have explicitly set tab items, or they have a data item source set.
+        // To move a tab left or right with explicitly set tab items, we'll remove and replace the tab item itself.
+        // 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.
+        int index = tabViewListView.IndexFromContainer(item);
+
+        if (index > 0)
+        {
+            MenuFlyoutItem moveLeftItem = new() { Text = "Move tab left" };
+            moveLeftItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
+                    itemsSourceList.RemoveAt(index);
+                    itemsSourceList.Insert(index - 1, item);
+                }
+                else
+                {
+                    var item = tabView.TabItems[index];
+                    tabView.TabItems.RemoveAt(index);
+                    tabView.TabItems.Insert(index - 1, item);
+                }
+            };
+            contextMenu.Items.Add(moveLeftItem);
+        }
+
+        if (index < tabViewListView.Items.Count - 1)
+        {
+            MenuFlyoutItem moveRightItem = new() { Text = "Move tab right" };
+            moveRightItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
+                    itemsSourceList.RemoveAt(index);
+                    itemsSourceList.Insert(index + 1, item);
+                }
+                else
+                {
+                    var item = tabView.TabItems[index];
+                    tabView.TabItems.RemoveAt(index);
+                    tabView.TabItems.Insert(index + 1, item);
+                }
+            };
+            contextMenu.Items.Add(moveRightItem);
+        }
+
+        // If the context menu ended up with no items at all, then we'll prevent it from being shown.
path: WinUIGallery/Helpers/TabViewHelper.cs
user: login: godlytalias
body: This logic would be better to be at the caller side only right?
created_at: 2025-03-27T07:45:05Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,102 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
+    {
+        contextMenu.Items.Clear();
+
+        var item = (TabViewItem)contextMenu.Target;
+        ListView tabViewListView = null;
+        TabView tabView = null;
+
+        DependencyObject current = item;
+
+        while (current != null)
+        {
+            DependencyObject parent = VisualTreeHelper.GetParent(current);
+
+            if (parent is ListView parentTabViewListView)
+            {
+                tabViewListView = parentTabViewListView;
+            }
+            else if (parent is TabView parentTabView)
+            {
+                tabView = parentTabView;
+            }
+
+            if (tabViewListView != null && tabView != null)
+            {
+                break;
+            }
+
+            current = parent;
+        }
+
+        if (tabViewListView == null || tabView == null)
+        {
+            return;
+        }
+
+        // First, if there are tabs to the left or to the right of the tab on which this context menu is opening,
+        // then we'll include menu items to move this tab to the left or to the right.
+        //
+        // There are two possible cases for tab views: either they have explicitly set tab items, or they have a data item source set.
+        // To move a tab left or right with explicitly set tab items, we'll remove and replace the tab item itself.
+        // 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.
+        int index = tabViewListView.IndexFromContainer(item);
+
+        if (index > 0)
+        {
+            MenuFlyoutItem moveLeftItem = new() { Text = "Move tab left" };
+            moveLeftItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
path: WinUIGallery/Helpers/TabViewHelper.cs
user: login: Hemantxk
body: Does index value gets copied over in this lambda for later use?
created_at: 2025-03-27T08:13:58Z
author_association: NONE
diff_hunk: @@ -0,0 +1,102 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
+    {
+        contextMenu.Items.Clear();
+
+        var item = (TabViewItem)contextMenu.Target;
+        ListView tabViewListView = null;
+        TabView tabView = null;
+
+        DependencyObject current = item;
+
+        while (current != null)
+        {
+            DependencyObject parent = VisualTreeHelper.GetParent(current);
+
+            if (parent is ListView parentTabViewListView)
+            {
+                tabViewListView = parentTabViewListView;
+            }
+            else if (parent is TabView parentTabView)
+            {
+                tabView = parentTabView;
+            }
+
+            if (tabViewListView != null && tabView != null)
+            {
+                break;
+            }
+
+            current = parent;
+        }
+
+        if (tabViewListView == null || tabView == null)
+        {
+            return;
+        }
+
+        // First, if there are tabs to the left or to the right of the tab on which this context menu is opening,
+        // then we'll include menu items to move this tab to the left or to the right.
+        //
+        // There are two possible cases for tab views: either they have explicitly set tab items, or they have a data item source set.
+        // To move a tab left or right with explicitly set tab items, we'll remove and replace the tab item itself.
+        // 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.
+        int index = tabViewListView.IndexFromContainer(item);
+
+        if (index > 0)
+        {
+            MenuFlyoutItem moveLeftItem = new() { Text = "Move tab left" };
+            moveLeftItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
+                    itemsSourceList.RemoveAt(index);
+                    itemsSourceList.Insert(index - 1, item);
+                }
+                else
+                {
+                    var item = tabView.TabItems[index];
+                    tabView.TabItems.RemoveAt(index);
+                    tabView.TabItems.Insert(index - 1, item);
+                }
+            };
+            contextMenu.Items.Add(moveLeftItem);
+        }
+
+        if (index < tabViewListView.Items.Count - 1)
+        {
+            MenuFlyoutItem moveRightItem = new() { Text = "Move tab right" };
path: WinUIGallery/Helpers/TabViewHelper.cs
user: login: Hemantxk
body: How about adding items like "Move the tab to the end" or "Move the tab to beginning"?
created_at: 2025-03-27T08:15:17Z
author_association: NONE
diff_hunk: @@ -0,0 +1,102 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
+    {
+        contextMenu.Items.Clear();
+
+        var item = (TabViewItem)contextMenu.Target;
+        ListView tabViewListView = null;
+        TabView tabView = null;
+
+        DependencyObject current = item;
+
+        while (current != null)
+        {
+            DependencyObject parent = VisualTreeHelper.GetParent(current);
+
+            if (parent is ListView parentTabViewListView)
+            {
+                tabViewListView = parentTabViewListView;
+            }
+            else if (parent is TabView parentTabView)
+            {
+                tabView = parentTabView;
+            }
+
+            if (tabViewListView != null && tabView != null)
+            {
+                break;
+            }
+
+            current = parent;
+        }
+
+        if (tabViewListView == null || tabView == null)
+        {
+            return;
+        }
+
+        // First, if there are tabs to the left or to the right of the tab on which this context menu is opening,
+        // then we'll include menu items to move this tab to the left or to the right.
+        //
+        // There are two possible cases for tab views: either they have explicitly set tab items, or they have a data item source set.
+        // To move a tab left or right with explicitly set tab items, we'll remove and replace the tab item itself.
+        // 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.
+        int index = tabViewListView.IndexFromContainer(item);
+
+        if (index > 0)
+        {
+            MenuFlyoutItem moveLeftItem = new() { Text = "Move tab left" };
+            moveLeftItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
+                    itemsSourceList.RemoveAt(index);
+                    itemsSourceList.Insert(index - 1, item);
+                }
+                else
+                {
+                    var item = tabView.TabItems[index];
+                    tabView.TabItems.RemoveAt(index);
+                    tabView.TabItems.Insert(index - 1, item);
+                }
+            };
+            contextMenu.Items.Add(moveLeftItem);
+        }
+
+        if (index < tabViewListView.Items.Count - 1)
+        {
+            MenuFlyoutItem moveRightItem = new() { Text = "Move tab right" };
+            moveRightItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
+                    itemsSourceList.RemoveAt(index);
+                    itemsSourceList.Insert(index + 1, item);
+                }
+                else
+                {
+                    var item = tabView.TabItems[index];
+                    tabView.TabItems.RemoveAt(index);
+                    tabView.TabItems.Insert(index + 1, item);
+                }
+            };
+            contextMenu.Items.Add(moveRightItem);
+        }
+
+        // If the context menu ended up with no items at all, then we'll prevent it from being shown.
+        if (contextMenu.Items.Count == 0)
+        {
+            contextMenu.Hide();
path: WinUIGallery/Helpers/TabViewHelper.cs
user: login: Hemantxk
body: As my comment on previous PR: this should be the job of caller.
created_at: 2025-03-27T08:16:23Z
author_association: NONE
diff_hunk: @@ -0,0 +1,102 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
+    {
+        contextMenu.Items.Clear();
+
+        var item = (TabViewItem)contextMenu.Target;
path: WinUIGallery/Helpers/TabViewHelper.cs
user: login: Hemantxk
body: We can have a null check after this point, if `item` is null return.
created_at: 2025-03-27T08:17:05Z
author_association: NONE
diff_hunk: @@ -0,0 +1,102 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
path: WinUIGallery/Helpers/TabViewHelper.cs
user: login: Hemantxk
body: should we rename this param -> menuFlyout?
created_at: 2025-03-27T08:17:33Z
author_association: NONE
diff_hunk: @@ -0,0 +1,102 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
+    {
+        contextMenu.Items.Clear();
+
+        var item = (TabViewItem)contextMenu.Target;
+        ListView tabViewListView = null;
+        TabView tabView = null;
+
+        DependencyObject current = item;
+
+        while (current != null)
+        {
+            DependencyObject parent = VisualTreeHelper.GetParent(current);
+
+            if (parent is ListView parentTabViewListView)
+            {
+                tabViewListView = parentTabViewListView;
+            }
+            else if (parent is TabView parentTabView)
+            {
+                tabView = parentTabView;
+            }
+
+            if (tabViewListView != null && tabView != null)
+            {
+                break;
+            }
+
+            current = parent;
+        }
+
+        if (tabViewListView == null || tabView == null)
+        {
+            return;
+        }
+
+        // First, if there are tabs to the left or to the right of the tab on which this context menu is opening,
+        // then we'll include menu items to move this tab to the left or to the right.
+        //
+        // There are two possible cases for tab views: either they have explicitly set tab items, or they have a data item source set.
+        // To move a tab left or right with explicitly set tab items, we'll remove and replace the tab item itself.
+        // 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.
+        int index = tabViewListView.IndexFromContainer(item);
+
+        if (index > 0)
+        {
+            MenuFlyoutItem moveLeftItem = new() { Text = "Move tab left" };
+            moveLeftItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
path: WinUIGallery/Helpers/TabViewHelper.cs
user: login: sabareesanms
body: yes. it will get copied over. 
created_at: 2025-03-28T09:59:13Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,102 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
+    {
+        contextMenu.Items.Clear();
+
+        var item = (TabViewItem)contextMenu.Target;
+        ListView tabViewListView = null;
+        TabView tabView = null;
+
+        DependencyObject current = item;
+
+        while (current != null)
+        {
+            DependencyObject parent = VisualTreeHelper.GetParent(current);
+
+            if (parent is ListView parentTabViewListView)
+            {
+                tabViewListView = parentTabViewListView;
+            }
+            else if (parent is TabView parentTabView)
+            {
+                tabView = parentTabView;
+            }
+
+            if (tabViewListView != null && tabView != null)
+            {
+                break;
+            }
+
+            current = parent;
+        }
+
+        if (tabViewListView == null || tabView == null)
+        {
+            return;
+        }
+
+        // First, if there are tabs to the left or to the right of the tab on which this context menu is opening,
+        // then we'll include menu items to move this tab to the left or to the right.
+        //
+        // There are two possible cases for tab views: either they have explicitly set tab items, or they have a data item source set.
+        // To move a tab left or right with explicitly set tab items, we'll remove and replace the tab item itself.
+        // 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.
+        int index = tabViewListView.IndexFromContainer(item);
+
+        if (index > 0)
+        {
+            MenuFlyoutItem moveLeftItem = new() { Text = "Move tab left" };
+            moveLeftItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
+                    itemsSourceList.RemoveAt(index);
+                    itemsSourceList.Insert(index - 1, item);
+                }
+                else
+                {
+                    var item = tabView.TabItems[index];
+                    tabView.TabItems.RemoveAt(index);
+                    tabView.TabItems.Insert(index - 1, item);
+                }
+            };
+            contextMenu.Items.Add(moveLeftItem);
+        }
+
+        if (index < tabViewListView.Items.Count - 1)
+        {
+            MenuFlyoutItem moveRightItem = new() { Text = "Move tab right" };
path: WinUIGallery/Helpers/TabViewHelper.cs
user: login: sabareesanms
body: We added these similar to edge and PowerShell windows. It is good use case. We can add this based on requirements. @Hemantxk 
created_at: 2025-03-28T10:00:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,102 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
+    {
+        contextMenu.Items.Clear();
+
+        var item = (TabViewItem)contextMenu.Target;
+        ListView tabViewListView = null;
+        TabView tabView = null;
+
+        DependencyObject current = item;
+
+        while (current != null)
+        {
+            DependencyObject parent = VisualTreeHelper.GetParent(current);
+
+            if (parent is ListView parentTabViewListView)
+            {
+                tabViewListView = parentTabViewListView;
+            }
+            else if (parent is TabView parentTabView)
+            {
+                tabView = parentTabView;
+            }
+
+            if (tabViewListView != null && tabView != null)
+            {
+                break;
+            }
+
+            current = parent;
+        }
+
+        if (tabViewListView == null || tabView == null)
+        {
+            return;
+        }
+
+        // First, if there are tabs to the left or to the right of the tab on which this context menu is opening,
+        // then we'll include menu items to move this tab to the left or to the right.
+        //
+        // There are two possible cases for tab views: either they have explicitly set tab items, or they have a data item source set.
+        // To move a tab left or right with explicitly set tab items, we'll remove and replace the tab item itself.
+        // 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.
+        int index = tabViewListView.IndexFromContainer(item);
+
+        if (index > 0)
+        {
+            MenuFlyoutItem moveLeftItem = new() { Text = "Move tab left" };
+            moveLeftItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
+                    itemsSourceList.RemoveAt(index);
+                    itemsSourceList.Insert(index - 1, item);
+                }
+                else
+                {
+                    var item = tabView.TabItems[index];
+                    tabView.TabItems.RemoveAt(index);
+                    tabView.TabItems.Insert(index - 1, item);
+                }
+            };
+            contextMenu.Items.Add(moveLeftItem);
+        }
+
+        if (index < tabViewListView.Items.Count - 1)
+        {
+            MenuFlyoutItem moveRightItem = new() { Text = "Move tab right" };
+            moveRightItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
+                    itemsSourceList.RemoveAt(index);
+                    itemsSourceList.Insert(index + 1, item);
+                }
+                else
+                {
+                    var item = tabView.TabItems[index];
+                    tabView.TabItems.RemoveAt(index);
+                    tabView.TabItems.Insert(index + 1, item);
+                }
+            };
+            contextMenu.Items.Add(moveRightItem);
+        }
+
+        // If the context menu ended up with no items at all, then we'll prevent it from being shown.
path: WinUIGallery/Helpers/TabViewHelper.cs
user: login: sabareesanms
body: Updated
created_at: 2025-03-28T10:20:38Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,102 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
+    {
+        contextMenu.Items.Clear();
+
+        var item = (TabViewItem)contextMenu.Target;
+        ListView tabViewListView = null;
+        TabView tabView = null;
+
+        DependencyObject current = item;
+
+        while (current != null)
+        {
+            DependencyObject parent = VisualTreeHelper.GetParent(current);
+
+            if (parent is ListView parentTabViewListView)
+            {
+                tabViewListView = parentTabViewListView;
+            }
+            else if (parent is TabView parentTabView)
+            {
+                tabView = parentTabView;
+            }
+
+            if (tabViewListView != null && tabView != null)
+            {
+                break;
+            }
+
+            current = parent;
+        }
+
+        if (tabViewListView == null || tabView == null)
+        {
+            return;
+        }
+
+        // First, if there are tabs to the left or to the right of the tab on which this context menu is opening,
+        // then we'll include menu items to move this tab to the left or to the right.
+        //
+        // There are two possible cases for tab views: either they have explicitly set tab items, or they have a data item source set.
+        // To move a tab left or right with explicitly set tab items, we'll remove and replace the tab item itself.
+        // 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.
+        int index = tabViewListView.IndexFromContainer(item);
+
+        if (index > 0)
+        {
+            MenuFlyoutItem moveLeftItem = new() { Text = "Move tab left" };
+            moveLeftItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
+                    itemsSourceList.RemoveAt(index);
+                    itemsSourceList.Insert(index - 1, item);
+                }
+                else
+                {
+                    var item = tabView.TabItems[index];
+                    tabView.TabItems.RemoveAt(index);
+                    tabView.TabItems.Insert(index - 1, item);
+                }
+            };
+            contextMenu.Items.Add(moveLeftItem);
+        }
+
+        if (index < tabViewListView.Items.Count - 1)
+        {
+            MenuFlyoutItem moveRightItem = new() { Text = "Move tab right" };
+            moveRightItem.Click += (s, args) =>
+            {
+                if (tabView.TabItemsSource is IList itemsSourceList)
+                {
+                    var item = itemsSourceList[index];
+                    itemsSourceList.RemoveAt(index);
+                    itemsSourceList.Insert(index + 1, item);
+                }
+                else
+                {
+                    var item = tabView.TabItems[index];
+                    tabView.TabItems.RemoveAt(index);
+                    tabView.TabItems.Insert(index + 1, item);
+                }
+            };
+            contextMenu.Items.Add(moveRightItem);
+        }
+
+        // If the context menu ended up with no items at all, then we'll prevent it from being shown.
+        if (contextMenu.Items.Count == 0)
+        {
+            contextMenu.Hide();
path: WinUIGallery/Helpers/TabViewHelper.cs
user: login: sabareesanms
body: Updated
created_at: 2025-03-28T10:20:48Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,102 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
+    {
+        contextMenu.Items.Clear();
+
+        var item = (TabViewItem)contextMenu.Target;
path: WinUIGallery/Helpers/TabViewHelper.cs
user: login: sabareesanms
body: Added a null check
created_at: 2025-03-28T10:21:03Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,102 @@
+using System.Collections;
+using Microsoft.UI.Xaml;
+using Microsoft.UI.Xaml.Controls;
+using Microsoft.UI.Xaml.Media;
+
+namespace WinUIGallery.Helpers;
+
+public static class TabViewHelper
+{
+    public static void PopulateTabViewContextMenu(MenuFlyout contextMenu)
path: WinUIGallery/Helpers/TabViewHelper.cs
user: login: sabareesanms
body: Renamed the param
created_at: 2025-03-28T10:21:20Z
author_association: CONTRIBUTOR

PR comments:
user: login: Hemantxk
created_at: 2025-03-31T07:32:04Z
body: /azp run
author_association: NONE
user: login: ayushjai30
created_at: 2025-03-31T08:24:16Z
body: /azp run
author_association: NONE
user: login: Saharsh979
created_at: 2025-03-31T08:38:53Z
body: I see that the pipeline is failing because of missing dependencies, turns out we were looking for a newer version of some package which was not there on the feed. Have updated the feed now!
author_association: NONE
user: login: Saharsh979
created_at: 2025-03-31T08:39:00Z
body: /azp run
author_association: NONE