简体   繁体   English

如何获取TabControl WPF的TabItem标头的宽度

[英]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. 我需要做的是先停止GridSplitter,然后再隐藏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. 因此,我想到的想法是将TabItems所有标头的ActualWidths总和绑定到TabControl的MinWidth或保留TabControl的Crid单元格。 But the problem is I am unable to access the Width of Header of TabItem so far. 但是问题是,到目前为止,我无法访问TabItem的页眉宽度。 One solution I found was place a TextBlock inside Tabitem.Header, declare its width and name it with x:Name. 我发现的一个解决方案是在Tabitem.Header内放置一个TextBlock,声明其宽度并使用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 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. 请注意,我已经实现了一种解决方案,但是如果选项卡是动态加载的,则它不能控制MinWidth。

<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 : 进行以下AttachedProperty只是有点乐趣:

XAML Usage XAML用法

<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 . 即使您使用TabControlItemsSource动态加载Tab,该解决方案也将起作用。 The TotalHeadersWidth will always receive the total headers width unless the tabs are wrapped in multiple rows. 除非选项卡包装在多行中,否则TotalHeadersWidth将始终接收总标题宽度。 In that case, it will use the ActualWidth of the TabControl itself which in your case, gives what we want. 在这种情况下,它将使用TabControl本身的ActualWidth ,在您的情况下,它将提供我们想要的内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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