6

I am using a compositecollection:

  • Comboboxitem with content "Select a vendor"
  • Collectioncontainer bound to a Observablecollection of Vendor objects

The desired functionality: the user has to select a vendor from the combobox. Selecting "Select a vendor" sets the Vendor property in the viewmodel to null.

I am getting an binding error. Any ideas how to fix this?

Error when debugging

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 'ComboBoxItem' (Name=''); target property is 'HorizontalContentAlignment' (type 'HorizontalAlignment')
System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=VerticalContentAlignment; DataItem=null; target element is 'ComboBoxItem' (Name=''); target property is 'VerticalContentAlignment' (type 'VerticalAlignment')

XAML

<ComboBox Name='cmbVendor'
            SelectedItem='{Binding Vendor, Converter={StaticResource ComboboxConverter}, Mode=TwoWay}'
            IsSynchronizedWithCurrentItem='True'>
    <ComboBox.Resources>
      <CollectionViewSource x:Key='VendorsCollection'
                            Source='{Binding Vendors}' />
      <DataTemplate DataType='{x:Type ComboBoxItem}'>
        <TextBlock Text='{Binding Content}' />
      </DataTemplate>
      <DataTemplate DataType='{x:Type objects:Vendor}'>
        <StackPanel>
          <TextBlock Text='{Binding Name}' />
        </StackPanel>
      </DataTemplate>
    </ComboBox.Resources>
    <ComboBox.ItemsSource>
      <CompositeCollection>
        <ComboBoxItem Content='Select a vendor' />
        <CollectionContainer Collection='{Binding Source={StaticResource VendorsCollection}}' />
      </CompositeCollection>
    </ComboBox.ItemsSource>
  </ComboBox>

ComboboxConverter

public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {

      var vendor = value as Vendor;
        if (vendor != null)
        {
            return vendor;
        }

        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var vendor = value as Vendor;
        if (vendor != null)
        {
            return vendor;
        }

        var comboboxItem = value as ComboBoxItem;
        if (comboboxItem != null)
        {
            return null;
        }
        return null;
    }
BertAR
  • 425
  • 3
  • 18

5 Answers5

8

Add to your App.xaml

<Style TargetType="{x:Type ComboBoxItem}">
    <Setter Property="HorizontalContentAlignment" Value="Left" />
    <Setter Property="VerticalContentAlignment" Value="Top" />
</Style>
NielW
  • 3,626
  • 1
  • 30
  • 38
3

The ComboBox (and other WPF controls) by default use a VirtualizingPanel for the ItemsPanel. If you change your items panel to not be a VirtualizingPanel or if you set the VirtualizingPanel.IsVirtualizing attached property to false, you will not see this runtime error.

<ComboBox Name="cmbVendor"
          SelectedItem="{Binding Vendor, Converter={StaticResource ComboboxConverter}, Mode=TwoWay}"
          IsSynchronizedWithCurrentItem="True"
          VirtualizingPanel.IsVirtualizing="False">
</ComboBox>

or

<ComboBox Name="cmbVendor"
          SelectedItem="{Binding Vendor, Converter={StaticResource ComboboxConverter}, Mode=TwoWay}"
          IsSynchronizedWithCurrentItem="True">
    <ComboBox.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel IsItemsHost="True" />
        </ItemsPanelTemplate>
    </ComboBox.ItemsPanel>
</ComboBox>

This is what worked for me instead of just ignoring the runtime error. I also tried changing the VirtualizationMode property of the VirtualizingStackPanel to both Standard and Recycling but that did not have any effect and the runtimes errors still occurred.

Finally, if you really do need virtualization because your ComboBox may contain many items (e.g. 100s) then I suggest overriding the Style or Template of the ComboBoxItem and setting the HorizontalContentAlignment and VerticalContentAlignment properties explicitly.

You can do this in the XAML Designer in Visual Studio by selecting your ComboBox in the Document Outline window and then right-clicking the ComboBox node and selecting Edit Additional Templates...Edit Generated Item Container (ItemContainerStyle). Then change the generated style for those two properties from:

<Style TargetType="{x:Type ComboBoxItem}">
    ...
    <Setter Property="HorizontalContentAlignment"
            Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
    <Setter Property="VerticalContentAlignment"
            Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" />
    ...
</Style>

to this or whatever you'd like:

<Style TargetType="{x:Type ComboBoxItem}">
    ...
    <Setter Property="HorizontalContentAlignment"
            Value="Stretch" />
    <Setter Property="VerticalContentAlignment"
            Value="Stretch" />
    ...
</Style>
tia.misu
  • 166
  • 1
  • 6
1

I got a similar issue but when overriding the ComboBoxItem template through a default style.

I wanted to have a custom template for my comboBox / comboBoxItem so I overrided the ComboBox Style and its template and inside it I setted the ItemContainerStyle (which is obviously the ComboBoxItem style) to override and apply a custom style (then template inside it).

code looks like this :

<Style TargetType="{x:Type ComboBox}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ComboBox">
                <!-- insert the combobox template -->
            </ControlTemplate>
        </Setter.Value>
    </Setter> 
    <Setter Property="ItemContainerStyle">
        <Setter.Value>
            <Style TargetType="ComboBoxItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ComboBoxItem">
                            <!-- insert your comboboxitem template -->
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Setter.Value>
    </Setter>
</Style>
Nearon
  • 71
  • 5
0

These binding errors are harmless and handled internally so you can safely just ignore them, or suppress them. Please refer to the following link for more information.

Resolving harmless binding errors in WPF: https://weblogs.asp.net/akjoshi/resolving-un-harmful-binding-errors-in-wpf

mm8
  • 163,881
  • 10
  • 57
  • 88
  • 1
    System.Diagnostics.PresentationTraceSources.DataBindingSource.Switch.Level = System.Diagnostics.SourceLevels.Critical helps, but that suppress all databinding errors in general – BertAR Nov 20 '17 at 13:04
  • It's either that or ignoring these warnings. As mentioned they are harmless and handled by the framework. – mm8 Nov 20 '17 at 13:06
  • 10
    Harmless they may be, but slows debug mode down while they all spit out – Epirocks Feb 07 '18 at 12:58
  • 1
    Not a valid solution when you have customers using your code. – NielW Jun 14 '21 at 21:11
  • Not so harmless when you are working with dte for an extension and they randomly show up leaving you with missing things. – gattsbr Sep 21 '22 at 00:01
0

Add to your App.xaml

<!-- https://stackoverflow.com/questions/47391020/cannot-find-source-for-binding-with-reference-relativesource-findancestor -->
<Style 
    x:Key="BugFreeListViewItemStyle"
    TargetType="{x:Type ListViewItem}"
    >
    <Setter Property="HorizontalContentAlignment" Value="Left" />
    <Setter Property="VerticalContentAlignment" Value="Top"/>
</Style>

and use it:

<ListView ItemContainerStyle="{StaticResource BugFreeListViewItemStyle}"/>
Konstantin S.
  • 1,307
  • 14
  • 19