Search code examples
c#wpfvisual-studio-2022tabviewtabitem

How to find TabItem by name?


I'm building a simple browser in WebView2 and I'm trying to add page titles to tabs. I've made the script to get the page title and tab name, just now I can't set the title itself.

Here's the script for sending the data to the main window with tabs. The text variable is the tab name.

public void UpdateTab(string text)
{
    MainWindow mainwindow = ((MainWindow)Application.Current.MainWindow);
    mainwindow.UpdateTabName(webView.CoreWebView2.DocumentTitle, text);
}

EDIT: Full code: (the strings can be in Polish)

MainWindow.xaml

<controls:MicaWindow x:Class="BringBackTheOldEdge.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:controls="clr-namespace:MicaWPF.Controls;assembly=MicaWPF"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:behaviors="http://schemas.microsoft.com/xaml/behaviors"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:BringBackTheOldEdge"
        xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
        mc:Ignorable="d"
        TitleBarType="WinUI"
        SystemBackdropType="Acrylic"
        ChangeTitleColorWhenInactive="False"
        Title=" " Height="450" Width="800" TitleBarHeight="40"
        >
    <controls:MicaWindow.TitleBarContent>
        <StackPanel Orientation="Horizontal">

            <TextBlock VerticalAlignment="Center">Edge</TextBlock>
        </StackPanel>
    </controls:MicaWindow.TitleBarContent>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0*"/>
            <ColumnDefinition Width="23*"/>
            <ColumnDefinition Width="2*"/>
        </Grid.ColumnDefinitions>
        <Rectangle   Fill="#55000000" Grid.ColumnSpan="3" Margin="0,-81,0,0"/>
        <TabControl x:Name="tabControl1" Grid.ColumnSpan="3" Background="{x:Null}" SelectionChanged="tabControl1_SelectionChanged">
            <TabItem x:Name="AddTabButton" Header="➕"/>
        </TabControl>
        <Menu x:Name="menu1" Margin="0,2,4,0" Background="{x:Null}" HorizontalAlignment="Right" VerticalAlignment="Top" Height="23" Width="28" HorizontalContentAlignment="Center" Grid.Column="2" MinWidth="28" MinHeight="24" BorderBrush="#66888888" BorderThickness="1,1,1,1">
            <MenuItem Header="⚙️" Height="20" Width="27" HorizontalContentAlignment="Center" FontWeight="Regular" HorizontalAlignment="Left" RenderTransformOrigin="0.765,0.502">
                <MenuItem Header="_1" IsCheckable="true" Background="{x:Null}" />
                <MenuItem Header="_2" IsCheckable="true" Background="{x:Null}" />
                <MenuItem Header="_3" IsCheckable="true" Background="{x:Null}" />
            </MenuItem>
        </Menu>
    </Grid>
</controls:MicaWindow>

MainWindow.xaml.cs

using System.Reflection.PortableExecutable;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;
using MicaWPF.Controls;
using MicaWPF.Core.Services;
using Microsoft.Web.WebView2.Core;
using static System.Net.Mime.MediaTypeNames;
using static System.Runtime.InteropServices.JavaScript.JSType;

namespace BringBackTheOldEdge
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : MicaWindow
    {  
        public int tabnum = 0;

        public MainWindow()
        {
            InitializeComponent();
            var converter = new System.Windows.Media.BrushConverter();
            var brush = (Brush)converter.ConvertFromString("#55000000");
            int idx = tabControl1.Items.Count;
            tabControl1.SelectedIndex = idx - 1;
            TabItem ti = new TabItem();
            ti.Header = idx / 2;
            int tabidx = idx - 1;
            RegisterName("tab0", ti);
            tabnum++;
            var ucont = new UserControl1();
            ti.Content = ucont;
            ucont.UpdateName("tab0");
            ti.Background = brush;
            tabControl1.Items.Insert(tabControl1.Items.Count - 1, ti);
            TabItem closeBtn = new TabItem();
            closeBtn.Header = "x";
            closeBtn.Background = brush;
            ti.IsSelected = true;
            tabControl1.Items.Insert(tabControl1.Items.Count - 1, closeBtn);
            tabControl1.SelectedIndex += 1;

        }

        private void tabControl1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            string tabItem = ((sender as TabControl).SelectedItem as TabItem).Header as string;

            switch (tabItem)
            {
                case "➕":
                    var converter = new System.Windows.Media.BrushConverter();
                    var brush = (Brush)converter.ConvertFromString("#55000000");
                    int idx = tabControl1.Items.Count;
                    tabControl1.SelectedIndex = idx - 1;
                    TabItem ti = new TabItem();
                    ti.Header = idx/2;
                    tabnum++;
                    RegisterName("tab" + tabnum.ToString(), ti);
                    var ucont = new UserControl1();
                    ti.Content = ucont;
                    ucont.UpdateName("tab" + tabnum.ToString());
                    ti.Background = brush;
                    TabItem closeBtn = new TabItem();
                    closeBtn.Header = "x";
                    closeBtn.Background = brush;
                    tabControl1.Items.Insert(tabControl1.Items.Count - 1, ti);
                    ti.IsSelected = true;
                    tabControl1.Items.Insert(tabControl1.Items.Count - 1, closeBtn);
                    break;
                case "x":
                    if (tabControl1.Items.Count == 3)
                    {
                        tabControl1.SelectedIndex -= 1;
                        if (MessageBox.Show("Czy chcesz zamknąć przeglądarkę?", "Uwaga", MessageBoxButton.OKCancel, MessageBoxImage.Warning) == MessageBoxResult.OK)
                        {
                            System.Windows.Application.Current.Shutdown();
                        }
                        break;
                    }
                    if (tabControl1.SelectedIndex != 1)
                    {
                        int idx1 = tabControl1.SelectedIndex - 1;
                        tabControl1.Items.RemoveAt(idx1);
                        int idx2 = tabControl1.SelectedIndex;
                        tabControl1.SelectedIndex-=2;
                        tabControl1.Items.RemoveAt(idx2);
                    }
                    else
                    {
                        int idx1 = tabControl1.SelectedIndex - 1;
                        tabControl1.Items.RemoveAt(idx1);
                        int idx2 = 0;
                        tabControl1.SelectedIndex += 1;
                        tabControl1.Items.RemoveAt(idx2);
                    }
                    break;
                default:
                    return;
            }
        }

        public void UpdateTabName(string text, string tab)
        {
             //here i need to update the tab names
        }
    }

}

BrowserDisplay.xaml

<UserControl x:Class="BringBackTheOldEdge.UserControl1"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:BringBackTheOldEdge"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Frame x:Name="viewer"  Source="BrowserPage.xaml"/>
</UserControl>

BrowserDisplay.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace BringBackTheOldEdge
{
    /// <summary>
    /// Logika interakcji dla klasy UserControl1.xaml
    /// </summary>
    public partial class UserControl1 : UserControl
    {
        public UserControl1()
        {
            InitializeComponent();
        }

        public void UpdateName(string text)
        {
            var page = new Page1() as Page1;
            page.UpdateName(text);
            
        }
    }
}

BrowserPage.xaml

<Page x:Class="BringBackTheOldEdge.Page1"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:controls="clr-namespace:MicaWPF.Controls;assembly=MicaWPF"
      xmlns:wv2="clr-namespace:Microsoft.Web.WebView2.Wpf;assembly=Microsoft.Web.WebView2.Wpf"
      xmlns:local="clr-namespace:BringBackTheOldEdge"
      mc:Ignorable="d" 
      d:DesignHeight="450" d:DesignWidth="800"
      Title="Page1">
    <Grid>
        <wv2:WebView2 x:Name="webView"
               Source="about:blank" Margin="0,43,0,0" SourceChanged="webView_SourceChanged" NavigationCompleted="webView_NavigationCompleted"
/>
        <controls:TextBox x:Name="textBox1" KeyDown="OnKeyDownHandler" Margin="163,0,0,0" VerticalAlignment="Top" Background="#00000000" Watermark="Wyszukaj lub wpisz adres..." Height="37" GotMouseCapture="textBox1_GotMouseCapture" GotKeyboardFocus="textBox1_GotKeyboardFocus"/>
        <controls:Button Content="←" HorizontalAlignment="Left" VerticalAlignment="Top" Height="37" Width="37" Margin="10,1,0,0" FontSize="10" Background="#00000000" BorderBrush="#00000000" Click="Button_Click"/>
        <controls:Button Content="→" HorizontalAlignment="Left" VerticalAlignment="Top" Height="37" Width="37" Margin="47,1,0,0" FontSize="10" Background="#00000000" BorderBrush="#00000000" Click="Button_Click_1"/>
        <controls:Button Content="🏠" HorizontalAlignment="Left" VerticalAlignment="Top" Height="37" Width="37" Margin="84,1,0,0" FontSize="10" Background="#00000000" BorderBrush="#00000000" Click="Button_Click_2"/>
        <controls:Button Content="🔃" HorizontalAlignment="Left" VerticalAlignment="Top" Height="37" Width="37" Margin="121,1,0,0" FontSize="10" Background="#00000000" BorderBrush="#00000000" Click="Button_Click_3"/>
    </Grid>
</Page>

BrowserPage.xaml.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using MicaWPF.Core.Services;
using Microsoft.Web.WebView2.Core;

namespace BringBackTheOldEdge
{
    /// <summary>
    /// Logika interakcji dla klasy Page1.xaml
    /// </summary>
    /// 
    
    public partial class Page1 : Page
    {
        public static string tabname; // Modifiable


        public Page1()
        {
            InitializeComponent();
            webView.Source = new System.Uri("https://www.msn.com/spartan/dhp?locale=en-US&market=US&enableregulatorypsm=0&enablecpsm=0&ishostisolationenforced=0&targetexperience=default");
            MicaWPFServiceUtility.AccentColorService.UpdateAccentsColorsFromWindows();
            textBox1.Focus();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            webView.GoBack();
        }

        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            webView.GoForward();
        }

        private void webView_SourceChanged(object sender, CoreWebView2SourceChangedEventArgs e)
        {
            string strr = webView.Source.ToString();

            if (webView.Source.ToString() == "https://www.msn.com/spartan/dhp?locale=en-US&market=US&enableregulatorypsm=0&enablecpsm=0&ishostisolationenforced=0&targetexperience=default")
            {
                strr = "";
            }
            if (strr.Contains("edge://"))
            {
                textBox1.Text = "❇️Edge | " + StripPrefix(strr, "edge://"); ;
            }
            else
            {
                textBox1.Text = "🔃Wczytywanie | " + StripPrefix(StripPrefix(strr, "https://"), "http://"); ;
            }
            
        }

        private void OnKeyDownHandler(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.Return)
            {
                if (textBox1.Text.Contains(':'))
                {
                    webView.Source = new System.Uri(textBox1.Text);
                }
                else
                {
                    webView.Source = new System.Uri("http://" + textBox1.Text);
                }

            }
        }

        public static string StripPrefix(string text, string prefix)
        {
            return text.StartsWith(prefix) ? text.Substring(prefix.Length) : text;
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            webView.Source = new System.Uri("https://www.msn.com/spartan/dhp?locale=en-US&market=US&enableregulatorypsm=0&enablecpsm=0&ishostisolationenforced=0&targetexperience=default");
        }

        private void webView_NavigationCompleted(object sender, CoreWebView2NavigationCompletedEventArgs e)
        {
            string strr = webView.Source.ToString();
            if (strr.Contains("https:"))
            {
                strr = "🔒Zabezpieczona | " + strr;
            }
            else
            {
                strr = "⚠️Potencjalnie niebezpieczna | " + strr;
            }
            if (webView.Source.ToString() == "https://www.msn.com/spartan/dhp?locale=en-US&market=US&enableregulatorypsm=0&enablecpsm=0&ishostisolationenforced=0&targetexperience=default")
            {
                strr = "";
            }
            textBox1.Text = StripPrefix(StripPrefix(strr, "https://"), "http://"); ;

            UpdateTab(tabname);
        }

        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            webView.Reload();
        }

        private void textBox1_GotMouseCapture(object sender, MouseEventArgs e)
        {
            textBox1.SelectAll();
        }

        private void textBox1_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
        {

        }

        public void UpdateName(string text)
        {
            tabname = text;
        }

        public void UpdateTab(string text)
        {
            MainWindow mainwindow = ((MainWindow)Application.Current.MainWindow);
            mainwindow.UpdateTabName(webView.CoreWebView2.DocumentTitle, text);
        }
    }
}


Solution

  • Quick Solution: Improve UpdateTabName

    public void UpdateTabName(string text, string tab)
    {
        var list = tabControl1.Items.Cast<TabItem>().ToList();
        TabItem tabItem;
        if (tab.Equals("tab0"))
        {
            tabItem = list.Where(p => p.Name.Equals("tab1")).FirstOrDefault();
        }
        else
        {
            tabItem = list.Where(p => p.Name.Equals(tab)).FirstOrDefault();
        }
        tabItem.Header = text;
    
    }
    

    In the tabControl1_SelectionChanged method, add the following code above RegisterName("tab" + tabnum.ToString(), ti);

    ti.Name = "tab" + tabnum.ToString();
    RegisterName("tab" + tabnum.ToString(), ti);
    

    I found other bugs in your project, you can check it out.

    Bug1: Your RegisterName method seems to have no effect

    Solution: Use ti.Name = "tab" + tabnum.ToString(); to name

    Bug2: The tabControl1_SelectionChanged method was executed when the first TabItem was created, but the name of the TabItem was wrong

    Solution: Here I will use conditional judgment to solve your initial problem, and you can improve your logic later

    Bug3: There is a delay between TabItem creation and Header update

    Solution: In tabControl1_SelectionChanged

    TabItem ti = new TabItem();
    ti.Header = idx / 2;
    

    ti.Header can directly give the correct text, so there is no need to execute UpdateTabName