让 WPF Tabcontrol 高度假设最大项目的高度?

Posted

技术标签:

【中文标题】让 WPF Tabcontrol 高度假设最大项目的高度?【英文标题】:Let WPF Tabcontrol height assume height of largest item? 【发布时间】:2010-11-07 14:37:15 【问题描述】:

有没有办法让 tabcontrol 获取最大选项卡项的大小(实际上,是 tabitem 的内容)?

由于 tabcontrol 没有分配特定的大小,它应该自动调整大小:它正确地做到了这一点,但是当您切换标签时,它会自动将自身调整为当前所选标签内容的高度(和宽度)。

我不希望发生调整大小,让 tabcontrol 假设最大项目的高度,但仍然让它自动调整大小。

有什么线索吗?我尝试对用作内容的每个元素的Height 属性进行数据绑定,以使用多重绑定,同时绑定Tabcontrol 的ActualHeightItems 属性。但是很可惜,内容元素的ActualHeight 始终为0。

        <TabItem Header="Core" > 
            <Grid Margin="5">
                <Grid.Height>
                    <MultiBinding Converter="Converters1:AllTabContentEqualHeightConverter">
                        <Binding Path="ActualHeight" RelativeSource="RelativeSource Mode=FindAncestor, AncestorType=x:Type TabControl"/>
                        <Binding Path="Items" RelativeSource="RelativeSource Mode=FindAncestor, AncestorType=x:Type TabControl"/>
                    </MultiBinding>
                </Grid.Height>

            ...

这个可以吗?

【问题讨论】:

【参考方案1】:

是的,可以做到:reuse-grid-rowdefinitions-for-each-tabitem

例子:

    <TabControl Grid.IsSharedSizeScope="True">
        <TabItem Header="Tab 1">
            <Grid >
                <Grid.RowDefinitions>
                    <RowDefinition SharedSizeGroup="xxx"/>
                </Grid.RowDefinitions>
            </Grid>
        </TabItem>
        <TabItem Header="Tab 2">
            <Grid >
                <Grid.RowDefinitions>
                    <RowDefinition SharedSizeGroup="xxx"/>
                </Grid.RowDefinitions>
            </Grid>
        </TabItem>
   </TabControl>

【讨论】:

关键是包含Grid.IsSharedSizeScope="True",我第一次错过了 - 没有它对我来说没有任何改变。另请注意,您不必在网格中使用 TabControl 来应用该值。 有没有办法通过 DataTemplate 应用它?我有一个 TabControl 绑定到一个集合来填充它的选项卡。我尝试设置行和列定义以在所有选项卡之间共享宽度/高度但没有成功(我在 TabControl 上设置了 Grid.IsSharedSizeScope="True") 这个解决方案确实有效。我在数据模板中尝试过。但它可能会导致 UI 很慢。取决于使用数据模板的位置。【参考方案2】:

问题在于TabControl 在您切换标签时会卸载并重新加载其内容。因此它只知道当前活动选项卡中内容的大小。您应该能够更改 TabControl,使其永远破坏其子级,并且它们始终存在(但可能隐藏)。

Eric Burke 的This blog post 应该可以帮助您入门。从我通过浏览他的帖子可以看出,您需要将其更改为:

在加载 TabControl 时加载所有子项。 子项在不活动时被隐藏而不是折叠

【讨论】:

这似乎是个好方法,但我自己解决了。无论如何,谢谢。【参考方案3】:

实际上,解决起来比我想的要容易。 因为无论如何我都有TabControl 的控制模板,所以我设置了ContentPresenter 的高度,以呈现选定的选项卡内容。我使用绑定到TabControl 的项目的转换器来执行此操作,必要时测量它们(使用Measure)并检查DesiredSize 是否有我需要的大小。

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    
        var items = value as ItemCollection;

        if (items == null)
            return null;

        double max = 0;
        foreach (TabItem item in items)
        
            var content = item.Content as FrameworkElement;
            if (content == null) continue;

            if (!content.IsMeasureValid)
                content.Measure(new Size(int.MaxValue, int.MaxValue));

            var height = content.DesiredSize.Height;
            if (max < height)
                max = height;
        

        return max;
    

效果很好,但有一些注意事项:

每个标签内容都应该是FrameworkElement 内容一旦加载就不会改变大小(因为转换器仅在 Items 属性更改时调用,即仅调用一次)。

【讨论】:

嗨@Inferis,你能告诉我你是如何绑定到选项卡控件内的 TabItem 集合的吗?我似乎找不到这个问题的答案。【参考方案4】:

这对我来说与上面显示的Grid.IsSharedSizeScope 方法一起使用。

请注意,使用 SetCurrentValue 而不是仅设置 SelectedIndex 属性 - 这样我们就可以保留现有的绑定:

private void TabControl_OnLoaded(object sender, RoutedEventArgs e)

    //NOTE: loop through tab items to force measurement and size the tab control to the largest tab
    TabControl tabControl = (TabControl)sender;

    // backup selection
    int indexItemLast = tabControl.SelectedIndex;

    int itemCount = tabControl.Items.Count;

    for (
        int indexItem = (itemCount - 1);
        indexItem >= 0;
        indexItem--)
    
        tabControl.SetCurrentValue(Selector.SelectedIndexProperty, indexItem);
        tabControl.UpdateLayout();
    

    // restore selection
    tabControl.SetCurrentValue(Selector.SelectedIndexProperty, indexItemLast);

【讨论】:

【参考方案5】:

它可能不是正确的 WPF 方式,但是,如果您已经拥有所有内容元素,您可以在加载时循环它们并以编程方式设置 TabControl 的高度。

【讨论】:

这是唯一对我有用的解决方案(与 Grid.IsSharedSizeScope 一起使用),尽管必须在以编程方式选择的每个选项卡上调用 TabControl.UpdateLayout() 以强制进行布局测量。

以上是关于让 WPF Tabcontrol 高度假设最大项目的高度?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 TabControl 的项目绑定到 wpf 中的可观察集合?

WPF 选项卡控件样式

WPF TabControl在开始时没有选择的项目

WPF SelectedIndex 设置 TabControl 的问题

WPF 多个选项卡TabControl 页面分离

WPF多行TabControl而不重新排列行