Pourquoi les en-têtes d'onglets sont-ils affichés dans la zone de contenu des onglets d'un TabControl XAML?

StackOverflow https://stackoverflow.com/questions/1226622

Question

J'ai un TabControl dont ItemsSource est lié à une collection de vues observable (UserControls) ayant pour élément racine un TabItem . Toutefois, lorsqu’il est affiché, le texte En-tête apparaît dans le contenu de chaque TabItem, comme si le wrapper UserControl était à l'origine de conflits:

 alt text

TabControl se trouve dans SmartFormView.xaml:

.
<UserControl x:Class="TestApp.Views.SmartFormView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <StackPanel
        Margin="10">
        <TextBlock Text="{Binding Title}"
            FontSize="18"/>
        <TextBlock Text="{Binding Description}"
            FontSize="12"/>

        <TabControl
            Margin="0 10 0 0"
            ItemsSource="{Binding SmartFormAreaViews}"/>
    </StackPanel>
</UserControl>

Que dois-je changer pour que TabItems soit affiché en tant que TabItems dans TabControl?

Voici les vues TabItem appelées SmartFormAreaView.xaml:

.
<UserControl x:Class="TestApp.Views.SmartFormAreaView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <TabItem Header="This is the header">
        <StackPanel Margin="10">
            <TextBlock Text="this is the content"/>
        </StackPanel>
    </TabItem>
</UserControl>

Et voici où je crée et charge chaque vue dans la ObservableCollection :

var areas = from area in xmlDoc.Descendants("area")
            select area;
foreach (var area in areas)
{
    SmartFormArea smartFormArea = new SmartFormArea();
    smartFormArea.IdCode = area.Attribute("idCode").Value;
    smartFormArea.Title = area.Attribute("title").Value;
    SmartFormAreaPresenter smartFormAreaPresenter = new SmartFormAreaPresenter(smartFormArea);
    SmartFormAreaViews.Add(smartFormAreaPresenter.View as SmartFormAreaView);
}
Était-ce utile?

La solution

Pour tout contrôle ItemsControl, si les éléments ajoutés à sa collection Items (soit directement, soit via ItemsSource) ne sont pas une instance du conteneur d'éléments de ce contrôle, chaque élément est alors encapsulé dans une instance du conteneur d'éléments. Le conteneur d'élément est une classe telle que TabItem ou ListBoxItem. Le conteneur d'élément est normalement un ContentControl ou HeaderedContentControl et votre élément réel est affecté à sa propriété Content. Vous pouvez donc utiliser des modèles, etc. pour contrôler la présentation du contenu. Vous pouvez également attribuer un style au conteneur d'élément lui-même à l'aide de la propriété ItemContainerStyle de ItemControl.

Dans ce cas particulier, vous devez lier ItemsSource à une liste de SmartFormAreaPresenters. Ensuite, utilisez quelque chose comme ceci pour le contrôle des onglets:

<TabControl ItemsSource="{Binding SmartFormAreaPresenters}">
  <TabControl.ItemContainerStyle>
    <Style TargetType="{x:Type TabItem}">
      <Setter Property="Header" Value="{Binding HeaderText}" />
    </Style>
  </TabControl.ItemContainerStyle>

  <TabControl.ContentTemplate>
    <DataTemplate DataType="{x:Type local:SmartFormAreaPresenter}">
      <local:SmartFormAreaView />
    </DataTemplate>
  </TabControl.ContentTemplate>
</TabControl>

où HeaderText est une propriété appropriée sur votre SmartFormAreaPresenter. Vous devez également supprimer le TabItem de votre définition SmartFormAreaView. Le DataContext de chaque vue sera automatiquement défini sur le présentateur approprié.

Consultez le blog du Dr. WPF pour une excellente discussion. de divers sujets liés à ItemsControl.

Autres conseils

Le TabControl n'acceptera vos contrôles comme contrôles que s'ils peuvent être transtypés en TabItem , et non pas UserControl ou SmartFormAreaView, etc.

Donc, soit vous remplissez < TabItems avec votre arborescence visuelle, soit vous sous-classe TabItems , soit vous sous-classez le TabControl pour remplacer son IsItemItsOwnContainerOverride } méthode, pour accepter votre type en tant que conteneur.

La méthode devrait ressembler à ceci:

protected override bool IsItemItsOwnContainerOverride(object item)
{
    return item is YourControlTypeHere || item is TabItem;
}
scroll top