Vamos WPF TabControl altura assumir altura do maior produto?
-
21-08-2019 - |
Pergunta
Existe alguma maneira de ter a tabcontrol tomar o tamanho do maior item de guia (bem, na verdade, o conteúdo do TabItem)?
Uma vez que o tabcontrol não tem tamanho específico designado deve dimensionamento automático:. Ele faz isso corretamente, mas quando você alternar guias automaticamente redimensiona-se à altura (e largura) do conteúdo da guia selecionada no momento
Eu não quero o redimensionamento acontecer, e deixar o tabcontrol assumir a altura do maior item, mas ainda tem dimensionamento automático em si.
Qualquer pistas? Tentei ligação de dados para a propriedade Height
de cada elemento usado como conteúdo ao utilizar um MultiBinding, com ligações tanto no ActualHeight
e as propriedades Items
do TabControl. Mas, infelizmente, o ActualHeight
dos elementos de conteúdo é sempre 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>
...
Pode ser feito?
Solução 3
Na verdade, foi mais fácil de resolver que eu pensava.
Desde que eu tinha um ControlTemplate para o TabControl
qualquer maneira, eu definir a altura do ContentPresenter
apresentar o conteúdo guia selecionada. I fazer isso usando um conversor que se liga aos itens do TabControl
, medidas los se necessário (utilizando Measure
) e verifica DesiredSize
para a necessidade tamanho que.
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;
}
Isso funciona muito bem, com algumas ressalvas:
- todos os conteúdos guia deve ser um
FrameworkElement
- o conteúdo não alterar o tamanho, uma vez que são carregados (porque o conversor só é chamado quando as mudanças de itens de propriedade, ou seja, apenas uma vez).
Outras dicas
Sim, pode ser feito: reutilização-grid-RowDefinitions-para-cada-TabItem
Exemplo:
<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>
O problema é que as descarrega TabControl
e recarrega seu conteúdo como você alternar guias. Por isso, só sabe sobre o tamanho do conteúdo na guia ativo no momento. Você deve ser capaz de mudar o TabControl tal que não destrói seus filhos, e eles estão sempre presentes (mas talvez oculto).
Este post por Eric Burke deverá fazê-lo começado. Do que eu posso dizer por desnatação seu post, você precisará alterá-lo de tal forma que:
- Todas as crianças são carregados quando o
TabControl
é carregado. - As crianças estão escondidos em vez de colapso quando estão inativos
Provavelmente não é na forma como WPF adequada, mas, se você já tem todos os elementos de conteúdo, talvez você possa percorrer-los em carga e definir a altura do TabControl
programaticamente.
Isso funcionou para mim em conjunto com abordagem Grid.IsSharedSizeScope
mostrado acima.
Note que SetCurrentValue
é usado em vez de apenas definir a propriedade SelectedIndex
- desta forma podemos manter possíveis ligações existentes:
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);
}