让 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 的ActualHeight
和Items
属性。但是很可惜,内容元素的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 中的可观察集合?