简体   繁体   中英

How to get Width of header of a TabItem of TabControl WPF

What I need to do is stop GridSplitter before going far beyond and thus hiding the TabControl. So the idea that hit upon my mind is to Bind the sum of ActualWidths of all Headers of TabItems to the MinWidth of TabControl or the Crid Cell keeping the TabControl. But the problem is I am unable to access the Width of Header of TabItem so far. One solution I found was place a TextBlock inside Tabitem.Header, declare its width and name it with x:Name. But using the width this way doesn't gives the total Width of the Header the includes margins and paddings etc, thus it doesn't work even near to accuracy.

UPDATE

Well, here is the code. Note that I have implemented one of the solutions but it does not control the MinWidth if tabs were loaded dynamically.

<Grid Background="#FFD6DBE9" Height="614" Width="1109">
        <Grid.RowDefinitions>
            <RowDefinition Height="89"/>
            <RowDefinition Height="Auto" MinHeight="{Binding ActualHeight, ElementName=gridNotificationsHeader}"/>
            <RowDefinition Height="494*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="400*" MinWidth="{Binding MinWidth, ElementName=tabDataEntities}"/>
            <ColumnDefinition Width="Auto"/>
            <ColumnDefinition Width="144*">
                <ColumnDefinition.MinWidth>
                    <MultiBinding Converter="{StaticResource StringSumtoIntConvert}">
                        <Binding ElementName="cdLblNotificationsHeader" Path="MinWidth"/>
                        <Binding ElementName="cdBtnNotificationsClose" Path="ActualWidth"/>
                    </MultiBinding>
                </ColumnDefinition.MinWidth>
            </ColumnDefinition>

        </Grid.ColumnDefinitions>
        <GridSplitter x:Name="gridSplitter" Grid.Column="1" HorizontalAlignment="Center" Grid.Row="1" Width="2" Grid.RowSpan="2"/>
        <Grid x:Name="gridNotificationsHeader" Grid.Column="2" Background="#FF657695" 
          Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition x:Name="cdLblNotificationsHeader" MinWidth="{Binding Width, ElementName=lblNotificationsHeader}"/>
                <ColumnDefinition x:Name="cdBtnNotificationsClose" Width="Auto"/>
            </Grid.ColumnDefinitions>
            <Label x:Name="lblNotificationsHeader" Content="Notifications" VerticalAlignment="Top" 
               FontSize="14.667" Height="30" Foreground="#FFEBF0EE" HorizontalAlignment="Left" Width="92"/>
            <Button x:Name="btnNotificationsClose" Content="X" 
                Margin="0,5,8,0" VerticalAlignment="Top" Width="20" FontFamily="Verdana" HorizontalAlignment="Right" Background="Transparent" FontSize="13.333" Foreground="Black" Grid.Column="1"/>
        </Grid>
        <TabControl x:Name="tabDataEntities" Margin="0,0,5,10" Grid.Row="1" Grid.RowSpan="2" FontSize="12" Grid.ColumnSpan="1" MinWidth="{Binding ElementName=TabItemOne, Path=ActualWidth}">
            <TabItem x:Name="TabItemOne">
                <TabItem.Header>Tab Item</TabItem.Header>
                <Grid Background="#FFE5E5E5"/>
            </TabItem>
            <TabItem Header="TabItem">
                <Grid Background="#FFE5E5E5"/>
            </TabItem>
        </TabControl>
    </Grid>

As simple as that

<StackPanel>
    <TabControl>
        <TabItem Header="Hello world" Name="Tab1"/>
        <TabItem Header="Hello" Name="Tab2"/>
        <TabItem Header="world" Name="Tab3"/>
    </TabControl>
    <TextBlock Text="{Binding ElementName=Tab1, Path=ActualWidth}"/>
    <TextBlock Text="{Binding ElementName=Tab2, Path=ActualWidth}"/>
    <TextBlock Text="{Binding ElementName=Tab3, Path=ActualWidth}"/>
</StackPanel>

Just had a little fun doing the following AttachedProperty :

XAML Usage

<TabControl question32926699:TabControlHeaderWidthWatcher.WatchHeadersWidth="true"
            question32926699:TabControlHeaderWidthWatcher.TotalHeadersWidth="{Binding TotalWidth, Mode=OneWayToSource}">
  <TabItem Header="Tab Item 1" />
  <TabItem Header="Tab Item 2" />
</TabControl>

The attached property

public class TabControlHeaderWidthWatcher
{
    private static TabControl m_tabControl;

    public static readonly DependencyProperty WatchHeadersWidthProperty = DependencyProperty.RegisterAttached(
        "WatchHeadersWidth", typeof (bool), typeof (TabControlHeaderWidthWatcher), new PropertyMetadata(default(bool), PropertyChangedCallback));

    public static void SetWatchHeadersWidth(DependencyObject element, bool value)
    {
        element.SetValue(WatchHeadersWidthProperty, value);
    }

    public static bool GetWatchHeadersWidth(DependencyObject element)
    {
        return (bool)element.GetValue(WatchHeadersWidthProperty);
    }

    public static readonly DependencyProperty TotalHeadersWidthProperty = DependencyProperty.RegisterAttached(
        "TotalHeadersWidth", typeof (double), typeof (TabControlHeaderWidthWatcher), new PropertyMetadata(default(double)));

    public static void SetTotalHeadersWidth(DependencyObject element, double value)
    {
        element.SetValue(TotalHeadersWidthProperty, value);
    }

    public static double GetTotalHeadersWidth(DependencyObject element)
    {
        return (double) element.GetValue(TotalHeadersWidthProperty);
    }

    private static void PropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
    {
        m_tabControl = dependencyObject as TabControl;
        if (m_tabControl == null) return;

        ((INotifyCollectionChanged)m_tabControl.Items).CollectionChanged += CollectionChanged;
    }

    private static void CollectionChanged(object sender, EventArgs eventArgs)
    {
        foreach (var item in m_tabControl.Items)
        {
            var tabItem = item as TabItem;
            if (tabItem == null) continue;

            // Unsubscribe first in case it was there previously
            tabItem.SizeChanged -= TabItemOnSizeChanged;
            tabItem.SizeChanged += TabItemOnSizeChanged;
        }
    }

    private static void TabItemOnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
    {
        var totalWidth = 0.0;
        foreach (var item in m_tabControl.Items)
        {
            var tabItem = item as TabItem;
            if (tabItem == null) continue;

            totalWidth += tabItem.ActualWidth;
        }

        // When more than one row of tabs, the width of the TabControl is used
        var actualWidth = totalWidth > m_tabControl.ActualWidth ? m_tabControl.ActualWidth : totalWidth;
        SetTotalHeadersWidth(m_tabControl, actualWidth);
    }
}

This solution will work even if you load Tabs dynamically using the ItemsSource of the TabControl . The TotalHeadersWidth will always receive the total headers width unless the tabs are wrapped in multiple rows. In that case, it will use the ActualWidth of the TabControl itself which in your case, gives what we want.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM