.net wpf data-binding listbox itemspaneltemplate

.net - ListBox con Grid como ItemsPanelTemplate produce errores de enlace extraños



listbox itemtemplate wpf (12)

Acabo de encontrar el mismo tipo de error:

System.Windows.Data Error: 4: No se puede encontrar el origen del enlace con la referencia ''RelativeSource FindAncestor, AncestorType ='' System.Windows.Controls.ItemsControl '', AncestorLevel ='' 1 ''''. BindingExpression: Path = HorizontalContentAlignment; DataItem = null; el elemento objetivo es ''ListBoxItem'' (Name = ''''); la propiedad de destino es ''HorizontalContentAlignment'' (tipo ''HorizontalAlignment'')

Esto sucedió mientras realizaba un enlace como este:

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

A esta propiedad en mi objeto de contexto de datos:

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

Después de experimentar, descubrí que el error solo se activaba cuando el número de elementos excedía la altura visible de mi ListBox (por ejemplo, cuando aparecen barras de desplazamiento verticales). Inmediatamente pensé en la virtualización y probé esto:

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

Esto resolvió mi problema. Aunque preferiría mantener activada la virtualización, no usé más tiempo para sumergirme en ella. Mi aplicación es un poco compleja con niveles múltiples de cuadrículas, paneles de puertos, etc. y algunas llamadas a métodos asincrónicos. No pude reproducir el problema en una aplicación más simple.

Tengo un control ListBox y estoy presentando un número fijo de objetos ListBoxItem en un diseño de cuadrícula. Así que he configurado my ItemsPanelTemplate para que sea una Grilla.

Estoy accediendo a la cuadrícula desde el código subyacente para configurar RowDefinitions y ColumnDefinitions.

Hasta ahora todo está funcionando como espero. Tengo algunas implementaciones personalizadas de IValueConverter para devolver el Grid.Row y Grid.Column en que debe aparecer cada ListBoxItem.

Sin embargo, a veces recibo extraños errores de enlace, y no puedo entender exactamente por qué están sucediendo, o incluso si están en mi código.

Aquí está el error que recibo:

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

¿Alguien puede explicar lo que está pasando?

Ah, y, aquí está mi 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>


De acuerdo con la Información general de la plantilla de datos en MSDN, DataTemplates debe usar como ItemTemplate para definir cómo se presentan los datos, mientras que un Style se usará como ItemContainerStyle para dar estilo solo al contenedor generado, como ListBoxItem .

Sin embargo, parece que estás tratando de utilizar este último para hacer el trabajo del primero. No puedo recrear su situación sin mucho más código, pero sospecho que hacer un enlace de datos en el estilo contenedor podría estar tirando una llave en el supuesto árbol visual / lógico.

Tampoco puedo evitar pensar que un diseño personalizado de elementos basado en la información del elemento requiere la creación de un Panel personalizado. Probablemente sea mejor para el Panel personalizado diseñar los elementos que para los elementos que se distribuirán con un surtido de IValueConverters de Rube Goldberg.


El problema de enlace proviene del estilo predeterminado para ListBoxItem. De forma predeterminada, al aplicar estilos a elementos, WPF busca los estilos predeterminados y aplica cada propiedad que no se establece específicamente en el estilo personalizado del estilo predeterminado. Consulte esta gran publicación de blog por Ian Griffiths para obtener más detalles sobre este comportamiento.

De regreso a nuestro problema Este es el estilo predeterminado para 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>

Tenga en cuenta que he eliminado el ControlTemplate para hacerlo compacto (he usado StyleSnooper - para recuperar el estilo). Puede ver que hay un enlace con una fuente relativa establecida en antecesor con tipo ItemsControl. Entonces, en su caso, los ListBoxItems que se crean al vincular no encontraron su ItemsControl. ¿Puede proporcionar más información con lo que es ItemsSource para su ListBox?

PD: Una forma de eliminar los errores es crear nuevos ajustadores para HorizontalContentAlignment y VerticalContentAlignment en su estilo personalizado.


Empecé a encontrarme con este problema, aunque mi ListBox tenía un conjunto Style y un ItemContainerStyle, y estos estilos nombrados ya habían definido HorizontalContentAlignment. Estaba usando los controles de CheckBox para activar / desactivar el filtrado en vivo en mi ListBox y esto parecía estar causando que los elementos salgan del estilo predeterminado en lugar de mis estilos asignados. La mayoría de los errores ocurrirían la primera vez que se activara el filtrado en vivo, pero a partir de entonces continuaría arrojando 2 errores en cada cambio. Me parece interesante que exactamente 2 registros en mi colección estaban vacíos y, por lo tanto, no tenían nada que mostrar en el artículo. Así que esto parece haber contribuido. Planeo crear datos predeterminados para que se muestren cuando un registro está vacío.

La sugerencia de Carter funcionó para mí. Agregar un estilo "predeterminado" separado sin clave y un TargetType = "ListBoxItem" que definió la propiedad HorizontalContentAlignment resolvió el problema. Ni siquiera necesité establecer la propiedad OverridesDefaultStyle para ello.


Esta es una amalgama de las otras respuestas aquí, pero para mí, tuve que aplicar el Setter en dos lugares para resolver el error, aunque esto fue cuando usé un VirtualizingWrapPanel personalizado.

Si elimino una de las siguientes declaraciones Setter , mis errores vuelven a aparecer.

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

Realmente no tengo tiempo para investigar más en este momento, pero sospecho que está relacionado con el estilo predeterminado que JTango menciona en su respuesta: realmente no estoy personalizando mi plantilla en gran medida.

Creo que hay más kilometraje de las otras respuestas, pero pensé en publicarlo por si ayuda a alguien en el mismo barco.

La respuesta de David Schmitt parece que podría describir la causa raíz.


Establecer OverridesDefaultStyle to True en su ItemContainerStyle también solucionará estos problemas.

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


Este es un problema común con ListBoxItem y otros efímeros *Item Contenedores de *Item . Se crean de forma asincrónica / sobre la marcha, mientras que ItemsControl se carga / procesa. Tiene que adjuntarse al evento StatusChanged y esperar a que Status se convierta en ItemsGenerated antes de intentar acceder a ellos.


Esto funcionó para mí. Pon esto en tu archivo Application.xaml.

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

de...

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


Otra solución / solución que funcionó para mí fue suprimir estos errores (en realidad, parece más apropiado llamarlos advertencias) al establecer el nivel de cambio de fuente de enlace de datos como crítico en el constructor de la clase o en una ventana de nivel superior -

#if DEBUG System.Diagnostics.PresentationTraceSources.DataBindingSource.Switch.Level = System.Diagnostics.SourceLevels.Critical; #endif

Ref .: Cómo suprimir el mensaje de advertencia de error System.Windows.Data


Si desea reemplazar por completo la plantilla ListBoxItem modo que no haya ninguna selección visible (tal vez desee tener el aspecto de ItemsControl con el comportamiento de agrupar / etc de ListBox ), puede usar este estilo:

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

Esta plantilla también excluye el contenedor de Border estándar. Si lo necesita, puede usar reemplazar la plantilla con esto:

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

Si no necesita todos estos valores de TemplateBinding , puede eliminar algunos para el rendimiento.


Simplemente crear un estilo predeterminado para el tipo "ComboBoxItem" no funciona, porque lo sobrescribe el valor predeterminado "ItemContainerStyle" de ComboBox. Para deshacerte de esto, necesitas cambiar el "ItemContainerStyle" por defecto para ComboBoxes, así:

<Style TargetType="ComboBox"> <Setter Property="ItemContainerStyle"> <Setter.Value> <Style TargetType="ComboBoxItem"> <Setter Property="HorizontalContentAlignment" Value="Left" /> <Setter Property="VerticalContentAlignment" Value="Center" /> </Style> </Setter.Value> </Setter> </Style>


Tuve el mismo problema que tú y solo quería compartir cuál fue mi solución. He intentado todas las opciones de esta publicación, pero la última fue la mejor para mí, gracias a Chris.

Entonces mi código:

<ListBox.Resources> <Style x:Key="listBoxItemStyle" TargetType="ListBoxItem"> <Setter Property="HorizontalContentAlignment" Value="Center" /> <Setter Property="VerticalContentAlignment" Value="Center" /> <Setter Property="MinWidth" Value="24"/> <Setter Property="IsEnabled" Value="{Binding IsEnabled}"/> </Style> <Style TargetType="ListBoxItem" BasedOn="{StaticResource listBoxItemStyle}"/> </ListBox.Resources> <ListBox.ItemContainerStyle> <Binding Source="{StaticResource listBoxItemStyle}"/> </ListBox.ItemContainerStyle> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel Orientation="Horizontal" IsItemsHost="True" MaxWidth="170"/> </ItemsPanelTemplate> </ListBox.ItemsPanel>

También descubrí que este error no aparece cuando ItemsPanelTemplate personalizado no existe.