37 votes

ListBox avec Grid comme ItemsPanelTemplate produit des erreurs de liaison étranges

J'ai un contrôle ListBox et je vais présenter un nombre fixe de ListBoxItem objets dans une grille de mise en page. J'ai donc mis mon ItemsPanelTemplate à une Grille.

Je suis l'accès à la Grille de code derrière pour configurer le RowDefinitions et ColumnDefinitions.

Jusqu'à présent, c'est tout ce travail que j'attends. J'ai quelques personnalisé IValueConverter implémentations pour le retour de la Grille.Ligne et de la Grille.Colonne de chaque ListBoxItem devrait apparaître.

Cependant je obtenir bizarre de liaison des erreurs parfois, et je ne peux pas comprendre exactement pourquoi ils sont qui se passe, ou même si elles sont dans mon code.

Voici l'erreur que je reçois:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=HorizontalContentAlignment; DataItem=null; target element is 'ListBoxItem' (Name=''); target property is 'HorizontalContentAlignment' (type 'HorizontalAlignment')

Quelqu'un peut-il expliquer ce qu'il se passe?

Oh, et voici mon code XAML:

<UserControl.Resources>
    <!-- Value Converters -->
    <v:GridRowConverter x:Key="GridRowConverter" />
    <v:GridColumnConverter x:Key="GridColumnConverter" />
    <v:DevicePositionConverter x:Key="DevicePositionConverter" />
    <v:DeviceBackgroundConverter x:Key="DeviceBackgroundConverter" />

    <Style x:Key="DeviceContainerStyle" TargetType="{x:Type ListBoxItem}">
        <Setter Property="FocusVisualStyle" Value="{x:Null}" />
        <Setter Property="Background" Value="Transparent" />

        <Setter Property="Grid.Row" Value="{Binding Path=DeviceId, Converter={StaticResource GridRowConverter}}" />
        <Setter Property="Grid.Column" Value="{Binding Path=DeviceId, Converter={StaticResource GridColumnConverter}}" />

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListBoxItem}">
                    <Border CornerRadius="2" BorderThickness="1" BorderBrush="White" Margin="2" Name="Bd"
                            Background="{Binding Converter={StaticResource DeviceBackgroundConverter}}">
                        <TextBlock FontSize="12" HorizontalAlignment="Center" VerticalAlignment="Center" 
                                Text="{Binding Path=DeviceId, Converter={StaticResource DevicePositionConverter}}" >
                            <TextBlock.LayoutTransform>
                                <RotateTransform Angle="270" />
                            </TextBlock.LayoutTransform>
                        </TextBlock>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter TargetName="Bd" Property="BorderThickness" Value="2" />
                            <Setter TargetName="Bd" Property="Margin" Value="1" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>            
    </Style>        
</UserControl.Resources>

<Border CornerRadius="3" BorderThickness="3" Background="#FF333333" BorderBrush="#FF333333" >
    <Grid ShowGridLines="False">
        <Grid.RowDefinitions>
            <RowDefinition Height="15" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <Image Margin="20,3,3,3" Source="Barcode.GIF" Width="60" Stretch="Fill" />
        </StackPanel>

        <ListBox ItemsSource="{Binding}" x:Name="lstDevices" Grid.Row="1" 
                 ItemContainerStyle="{StaticResource DeviceContainerStyle}"
                 Background="#FF333333"
                 SelectedItem="{Binding SelectedDeviceResult, ElementName=root, Mode=TwoWay}" >
            <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <Grid>
                        <Grid.LayoutTransform>
                            <RotateTransform Angle="90" />
                        </Grid.LayoutTransform>                            
                    </Grid>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>
        </ListBox>
    </Grid>
</Border>

32voto

ligaz Points 1683

La liaison problème vient de la style par défaut pour ListBoxItem. Par défaut, lors de l'application de styles aux éléments WPF recherche les styles par défaut et s'applique chaque propriété qui n'est pas spécifiquement défini dans le style personnalisé de style par défaut. Reportez-vous à ce grand post de blog Par Ian Griffiths pour plus de détails sur ce comportement.

De retour à notre problème. Ici est le style par défaut pour ListBoxItem:

<Style
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:s="clr-namespace:System;assembly=mscorlib"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    TargetType="{x:Type ListBoxItem}">
    <Style.Resources>
       <ResourceDictionary/>
    </Style.Resources>
    <Setter Property="Panel.Background">
       <Setter.Value>
          <SolidColorBrush>
        #00FFFFFF
          </SolidColorBrush>
       </Setter.Value>
    </Setter>
    <Setter Property="Control.HorizontalContentAlignment">
       <Setter.Value>
          <Binding Path="HorizontalContentAlignment" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ItemsControl, AncestorLevel=1}"/>
       </Setter.Value>
    </Setter>
    <Setter Property="Control.VerticalContentAlignment">
       <Setter.Value>
          <Binding Path="VerticalContentAlignment" RelativeSource="{RelativeSource Mode=FindAncestor, AncestorType=ItemsControl, AncestorLevel=1}"/>
       </Setter.Value>
    </Setter>
    <Setter Property="Control.Padding">
       <Setter.Value>
          <Thickness>
        2,0,0,0
          </Thickness>
       </Setter.Value>
    </Setter>
    <Setter Property="Control.Template">
       <Setter.Value>
          <ControlTemplate TargetType="{x:Type ListBoxItem}">
             ...
          </ControlTemplate>
       </Setter.Value>
    </Setter>
 </Style>

Notez que j'ai supprimé les ControlTemplate pour le rendre compact (j'ai utilisé StyleSnooper pour récupérer le style). Vous pouvez voir qu'il y a une liaison avec une relative définir la source de l'ancêtre de type ItemsControl. Donc, dans votre cas, la ListBoxItems qui sont créés lors de la liaison n'ont pas trouvé leur ItemsControl. Pouvez-vous donner plus d'infos à ce qui est le ItemsSource pour votre ListBox?

P. S.: Une façon de supprimer les erreurs est de créer de nouvelles setters pour HorizontalContentAlignment et VerticalContentAlignment dans votre Style personnalisé.

25voto

JTango Points 151

La définition de OverridesDefaultStyle sur True dans votre ItemContainerStyle résoudra également ces problèmes.

 <Style TargetType="ListBoxItem">
    <Setter Property="OverridesDefaultStyle" Value="True"/>
    <!-- set the rest of your setters, including Template, here -->
</Style>
 

7voto

David Schmitt Points 29384

C'est un problème commun avec ListBoxItems et autres éphémères *Item des conteneurs. Ils sont créés de manière asynchrone/à la volée, tandis que l' ItemsControl est chargé/rendu. Vous devez joindre à l' ListBox.ItemContainerGenerators' StatusChanged d'événements et d'attendre que la situation devienne ItemsGenerated avant d'essayer d'y accéder.

2voto

SteffenSH Points 176

Je viens de rencontré le même type d'erreur:

Système.De Windows.Erreur De Données: 4 : Impossible de trouver la source de la liaison avec la référence 'RelativeSource FindAncestor, AncestorType='Système.De Windows.Les contrôles.ItemsControl', AncestorLevel='1". BindingExpression:Path=HorizontalContentAlignment; DataItem=null; élément cible est "ListBoxItem' (Name="); la propriété target est 'HorizontalContentAlignment' (type "HorizontalAlignment')

Ce qui s'est passé tout en faisant une liaison comme ceci:

<ListBox ItemsSource="{Binding Path=MyListProperty}"  />

Pour cette propriété sur mon objet de contexte de données:

public IList<ListBoxItem> MyListProperty{ get; set;}

Après quelques tests, j'ai découvert que l'erreur a été déclenché uniquement lorsque le nombre d'éléments de dépassement de la hauteur visible de ma ListBox (par exemple, lorsque vertical des barres de défilement apparaissent). J'ai donc immédiatement pensé à la virtualisation et essayé ceci:

<ListBox ItemsSource="{Binding Path=MyListProperty}" VirtualizingStackPanel.IsVirtualizing="False" />

Cela a résolu le problème pour moi. Bien que je préfère garder la virtualisation activée que je n'ai plus le temps de plonger. Ma demande est un peu sur le complexe de côté avec mulitiple niveaux de grilles, quai des panneaux etc. et certains asynch les appels de méthode. Je n'ai pas pu reproduire le problème dans une application plus simple.

1voto

Joel B Fant Points 14013

Selon les modèles de Données vue d'ensemble sur MSDN, DataTemplates doit être utilisé comme l' ItemTemplate pour définir la façon dont les données sont présentées, tandis qu'un Style seraient utilisés comme l' ItemContainerStyle de style que l'généré conteneur, tel qu' ListBoxItem.

Cependant, il semble que vous essayez d'utiliser ce dernier pour faire le travail de l'ancien. Je ne peux pas recréer votre situation, sans beaucoup plus de code, mais je pense que faire de la liaison de données dans le conteneur de style pourrait être jeter une clé dans l'hypothèse visuelle/arborescence logique.

Je ne peux pas aider mais penser qu'une mise en page personnalisée des éléments en fonction de l'élément de l'information appelle à la création d'une coutume Panel. C'est probablement mieux pour la coutume Panel de mise en page les articles que pour les éléments de laïcs eux-mêmes avec un Rube Goldberg assortiment de IValueConverters.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X