2009-07-02 19 views
12

¿Hay alguna manera de tener que tabcontrol tomar el tamaño del elemento de tabulación más grande (bueno, de hecho, el contenido del tabitem)?Deje que la altura del control de tabulación de WPF asuma la altura del artículo más grande?

Dado que el tabcontrol no tiene un tamaño específico asignado, debe autosize: lo hace correctamente, pero cuando cambia las pestañas automáticamente se redimensiona a la altura (y ancho) de los contenidos de la pestaña actualmente seleccionada.

No quiero que cambie el tamaño, y deje que el tabcontrol asuma la altura del elemento más grande, pero aún así haga que se autoestructure.

¿Alguna pista? Probé la vinculación de datos a la propiedad Height de cada elemento utilizado como contenido con el uso de multibinding, con enlaces en las propiedades ActualHeight y Items de Tabcontrol. Pero, por desgracia, la ActualHeight de los elementos de contenido es siempre 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> 

      ... 

se puede hacer esto?

Respuesta

5

En realidad, era más fácil de resolver de lo que pensaba. Ya que tenía una plantilla de control para el TabControl de todos modos, configuré la altura del ContentPresenter que presentaba el contenido de la pestaña seleccionada. Lo hago usando un convertidor que se une a los elementos del TabControl, los mide si es necesario (usando Measure) y comprueba DesiredSize para el tamaño que necesito.

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; 
    } 

que funciona muy bien, con algunas salvedades:

  • cada pestaña contenido debe ser un FrameworkElement
  • los contenidos no cambian de tamaño una vez que se cargan (debido a que el convertidor se llama solamente cuando la propiedad Artículos cambia, es decir, solo una vez).
+0

Hola @Inferis, ¿podrías decirme? ¿Cómo se une a la colección de TabItem dentro del control de pestañas? Parece que no puedo encontrar una respuesta para esto. – Zepee

6

El problema es que el TabControl descarga y vuelve a cargar su contenido cuando cambia de pestaña. Por lo tanto, solo conoce el tamaño del contenido en la pestaña actualmente activa. Debería poder cambiar el TabControl de manera que nunca destruya sus hijos, y siempre están presentes (pero quizás ocultos).

This blog post de Eric Burke debería comenzar. De lo que puedo decir por rozar su puesto, tendrá que cambiarlo tal que:

  • Todos los niños se cargan cuando se carga el TabControl.
  • Los niños están ocultos en lugar de colapsado cuando están inactivos
+0

Eso parece un buen enfoque, pero me acabo de resolver yo mismo. Gracias de cualquier manera. – Inferis

+0

Enlace roto. :( –

1

Probablemente no sea en la forma de WPF adecuada, pero, si ya tiene todos los elementos de contenido, tal vez podría bucle a través de ellos de la carga y ajustar la altura del TabControl programáticamente.

+0

Esta es la única solución que funcionó para mí (en conjunto es Grid.IsSharedSizeScope) aunque hay que llamar a 'TabControl.UpdateLayout()' en cada pestaña seleccionada mediante programación para forzar la medición del diseño. – Libor

17

Sí Se puede hacer: reuse-grid-rowdefinitions-for-each-tabitem

Ejemplo:

<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> 
+1

¡Simplemente genial! –

+3

La clave es incluir 'Grid.IsSharedSizeScope =" True "', me olvidé de que el primera vez, sin eso, nada ha cambiado para mí. También tenga en cuenta que no tiene que tener el 'TabControl' dentro de una grilla para aplicar ese valor. –

+1

¿Hay alguna manera de aplicar esto a través de una DataTemplate? Tengo un TabControl enlazado a una colección para poblar sus pestañas. Intenté configurar las definiciones de Fila y Columna para compartir ancho/alto en todas las pestañas sin éxito (hago Grid.IsSharedSizeScope = "True" en el TabControl) – Zepee

0

Esto funcionó para mí en conjunción con Grid.IsSharedSizeScope enfoque se muestra más arriba.

Tenga en cuenta que SetCurrentValue se utiliza en lugar de sólo la creación de la propiedad SelectedIndex - de esta manera mantenemos posibles consolidaciones 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); 
} 
Cuestiones relacionadas