[.net] ListBox mit Grid als ItemsPanelTemplate erzeugt seltsame Bindungsfehler


Answers

Wenn Sie in Ihrem ItemContainerStyle OverridesDefaultStyle auf True ItemContainerStyle werden auch diese Probleme ItemContainerStyle .

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

Ich habe ein ListBox-Steuerelement, und ich präsentiere eine feste Anzahl von ListBoxItem-Objekten in einem Rasterlayout. Also habe ich meine ItemsPanelTemplate auf ein Grid gesetzt.

Ich greife von hinten auf das Grid zu, um die RowDefinitions und ColumnDefinitions zu konfigurieren.

Bis jetzt läuft alles wie erwartet. Ich habe einige benutzerdefinierte IValueConverter-Implementierungen für die Rückgabe der Grid.Row und Grid.Column, die jedes ListBoxItem angezeigt werden soll.

Allerdings bekomme ich manchmal komische Bindungsfehler, und ich kann nicht genau herausfinden, warum sie passieren oder ob sie in meinem Code enthalten sind.

Hier ist der Fehler, den ich bekomme:

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')

Kann jemand erklären, was los ist?

Oh, und hier ist mein 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>




Ich habe mit diesem Problem begonnen, obwohl meine ListBox sowohl ein Style- als auch ein ItemContainerStyle-Set hatte - und diese benannten Stile hatten bereits HorizontalContentAlignment definiert. Ich habe CheckBox-Steuerelemente verwendet, um die Live-Filterung auf meiner ListBox ein- und auszuschalten, und dies schien die Elemente dazu zu veranlassen, statt der zugewiesenen Stile anstelle des Standardstils zu ziehen. Die meisten Fehler würden auftreten, wenn die Live-Filterung das erste Mal ausgelöst wird, aber danach würde sie bei jeder Änderung weiterhin 2 Fehler werfen. Ich finde es interessant, dass genau 2 Datensätze in meiner Sammlung leer waren und daher nichts in dem Artikel angezeigt werden mussten. Das scheint also bestanden zu haben. Ich plane, Standarddaten zu erstellen, die angezeigt werden sollen, wenn ein Datensatz leer ist.

Carters Vorschlag funktionierte für mich. Das Hinzufügen eines separaten "Standard" -Stils ohne Schlüssel und eines TargetType = "ListBoxItem", das die Eigenschaft HorizontalContentAlignment definierte, löste das Problem. Ich musste nicht einmal die OverridesDefaultStyle-Eigenschaft dafür festlegen.




Das hat für mich funktioniert. Fügen Sie dies in Ihre Application.xaml-Datei ein.

<Application.Resources>
    <Style TargetType="ListBoxItem">
        <Setter Property="HorizontalContentAlignment" Value="Left" />
        <Setter Property="VerticalContentAlignment" Value="Center" />
    </Style>
</Application.Resources>

von...

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/42cd1554-de7a




Wenn Sie die ListBoxItem Vorlage vollständig ersetzen ListBoxItem , sodass keine Auswahl sichtbar ist (vielleicht möchten Sie das Aussehen von ItemsControl mit dem Grouping / etc-Verhalten von ListBox ), dann können Sie diesen Stil verwenden:

<Style TargetType="ListBoxItem">
  <Setter Property="Margin" Value="2" />
  <Setter Property="FocusVisualStyle" Value="{x:Null}" />
  <Setter Property="OverridesDefaultStyle" Value="True" />
  <Setter Property="Template">
    <Setter.Value>
      <ControlTemplate TargetType="{x:Type ListBoxItem}">
        <ContentPresenter Content="{TemplateBinding ContentControl.Content}" 
                          HorizontalAlignment="Stretch" 
                          VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" 
                          SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
      </ControlTemplate>
    </Setter.Value>
  </Setter>
</Style>

Diese Vorlage schließt auch den standardmäßigen Border Wrapper aus. Wenn Sie das benötigen, können Sie die Vorlage hiermit ersetzen:

<Border BorderThickness="{TemplateBinding Border.BorderThickness}" 
        Padding="{TemplateBinding Control.Padding}" 
        BorderBrush="{TemplateBinding Border.BorderBrush}" 
        Background="{TemplateBinding Panel.Background}" 
        SnapsToDevicePixels="True">
  <ContentPresenter Content="{TemplateBinding ContentControl.Content}" 
                    ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}" 
                    HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}" 
                    VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}" 
                    SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</Border>

Wenn Sie nicht alle diese TemplateBinding Werte benötigen, können Sie einige für die Leistung entfernen.




Ich habe gerade die gleiche Art von Fehler gefunden:

System.Windows.Data Fehler: 4: Quelle zum Binden mit der Referenz 'RelativeSource FindAncestor, AncestorType =' System.Windows.Controls.ItemsControl ', AncestorLevel =' 1 '' konnte nicht gefunden werden. Bindungsexpression: Pfad = HorizontalContentAlignment; DataItem = null; Zielelement ist 'ListBoxItem' (Name = ''); target property ist 'HorizontalContentAlignment' (Typ 'HorizontalAlignment')

Dies ist während einer Bindung wie folgt geschehen:

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

Zu dieser Eigenschaft in meinem Datenkontextobjekt:

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

Nach einigen Experimenten stellte ich fest, dass der Fehler nur ausgelöst wurde, wenn die Anzahl der Elemente die sichtbare Höhe meiner ListBox überschritt (z. B. wenn vertikale Bildlaufleisten angezeigt werden). Also habe ich sofort an die Virtualisierung gedacht und das versucht:

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

Das löste das Problem für mich. Obwohl ich es vorziehen würde, die Virtualisierung eingeschaltet zu lassen, habe ich keine Zeit mehr verwendet, um in sie einzutauchen. Meine Anwendung ist ein bisschen auf der komplexen Seite mit mehreren Ebenen von Grids, Dock-Panels usw. und einige asynchrone Methodenaufrufe. Ich war nicht in der Lage, das Problem in einer einfacheren Anwendung zu reproduzieren.




Dies ist ein Amalgam der anderen Antworten hier, aber für mich musste ich den Setter an zwei Stellen anwenden, um den Fehler zu beheben, obwohl dies bei der Verwendung eines benutzerdefinierten VirtualizingWrapPanel

Wenn ich eine der folgenden Setter Deklarationen entferne, werden meine Fehler erneut angezeigt.

        <ListView>
            <ListView.Resources>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalContentAlignment" Value="Left" />
                    <Setter Property="VerticalContentAlignment" Value="Top" />
                </Style>
            </ListView.Resources>
            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalContentAlignment" Value="Left" />
                    <Setter Property="VerticalContentAlignment" Value="Top" />
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.ItemsPanel>
                <ItemsPanelTemplate>
                    <controls:VirtualizingWrapPanel />
                </ItemsPanelTemplate>
            </ListView.ItemsPanel>
        </ListView>

Ich habe nicht wirklich die Zeit, im Moment weiter nachzuforschen, aber ich vermute, es hängt mit dem Standardstil zusammen, den JTango in seiner Antwort erwähnt - ich passe meine Vorlage nicht wirklich an.

Ich denke, es gibt mehr Meilen, die man aus den anderen Antworten haben kann, aber ich dachte, ich würde dies posten, wenn es jemandem im selben Boot hilft.

David Schmitt's Antwort sieht so aus, als könnte sie die Ursache beschreiben.