2009-07-02 5 views
12

Есть ли какой-нибудь способ заставить tabcontrol взять размер самого большого элемента табуляции (ну, собственно, содержимое tabitem)?Позвольте WPF Tabcontrol height принять высоту самого большого элемента?

Поскольку tabcontrol не имеет определенного размера, он должен авторизоваться: он делает это правильно, но при переключении вкладок он автоматически изменяется на высоту (и ширину) содержимого текущей выбранной вкладки.

Я не хочу, чтобы изменение размера происходило, и пусть tabcontrol принимает высоту самого большого элемента, но все еще имеет его автоизображение.

Любые подсказки? Я попробовал привязку данных к свойству Height каждого элемента, используемого в качестве содержимого, для использования многосвязности, с привязками к объектам ActualHeight и Items свойств Tabcontrol. Но, увы, 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> 

      ... 

Можно ли это сделать?

ответ

5

На самом деле, было легче решить, что я думал. Так как в любом случае у меня была контрольная таблица для 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 изменяется, т.е. только один раз).
+0

Hi @Inferis вы могли бы рассказать мне как вы привязались к коллекции TabItem внутри элемента управления вкладкой? Кажется, я не могу найти ответ для этого. – Zepee

6

Проблема заключается в том, что TabControl выгружает и перезагружает его содержимое при переключении вкладок. Поэтому он знает только размер содержимого на текущей активной вкладке. Вы должны иметь возможность изменять TabControl таким образом, чтобы он никогда не уничтожал своих детей, и они всегда присутствуют (но могут быть скрыты).

This blog post от Eric Burke должно начаться. Из того, что я могу сказать, сократив его пост, вам нужно будет изменить его так, чтобы:

  • Все дети загружаются при загрузке TabControl.
  • Дети скрыты, а не разрушилась, когда они неактивны
+0

Это кажется хорошим подход, но я просто решил сам. Спасибо, в любом случае. – Inferis

+0

Неработающая ссылка. :( –

1

Это, вероятно, не надлежащим образом WPF, но, если у вас уже есть все элементы контента, вы могли бы, возможно, цикл через них на нагрузку и установить высота TabControl программно.

+0

Это единственное решение, которое сработало для меня (в соединении с Grid.IsSharedSizeScope), хотя нужно называть каждую из каждой вкладки, выбранной программно, чтобы заставить измерение макета. – Libor

17

Да, это может быть сделано: 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> 
+1

Просто блестящий !! –

+3

Ключ должен включать 'Grid.IsSharedSizeScope =" True "', я пропустил, что первый раз - без него ничего не изменилось для меня. Также обратите внимание, что вам не нужно иметь «TabControl» в сетке для применения этого значения. –

+1

Есть ли способ применить это, хотя DataTemplate? У меня есть TabControl связанный с коллекцией, чтобы заполнить ее вкладки. Я попытался установить определения строк и столбцов для совместного использования ширины/высоты на всех вкладках без успеха (я делаю Grid.IsSharedSizeScope = «True», установленный в TabControl) – Zepee

0

Это работает для меня в связи с 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); 
}