【问题标题】:Let WPF Tabcontrol height assume height of largest item?让 WPF Tabcontrol 高度假设最大项目的高度?
【发布时间】: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>

            ...

这个可以吗?

【问题讨论】:

    标签: wpf height tabcontrol multibinding


    【解决方案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() 以强制进行布局测量。
      猜你喜欢
      • 2016-11-01
      • 1970-01-01
      • 2014-06-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-05-17
      • 2019-03-26
      • 2013-07-28
      相关资源
      最近更新 更多