Search code examples
wpfdependency-propertiesxaml-binding

Binding to Dependency Properties within ItemsControl


I have an ItemsControl with an inline ItemsSource as below (simplified):

<UserControl>
    <ItemsControl>         
            <ItemsControl.ItemsSource>
               <x:Array Type="y:KeyData">
                  <y:KeyData Name="Name1"/>
                  <y:KeyData Name="Name2"/>
               </x:Array>
            </ItemsControl.ItemsSource>
    </ItemsControl>
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="{x:Type DateDifferences:KeyData}">
            <TextBlock Text="{Binding Name}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</UserControl>

I now want to bind another value to each KeyData item. I've tried the below:

<UserControl>
    <ItemsControl>         
            <ItemsControl.ItemsSource>
               <x:Array Type="y:KeyData">
                  <y:KeyData Name="Name1" Count="{Binding Count1}"/>
                  <y:KeyData Name="Name2" Count="{Binding Count2}"/>
               </x:Array>
            </ItemsControl.ItemsSource>
    </ItemsControl>
    <ItemsControl.ItemTemplate>
        <DataTemplate DataType="{x:Type DateDifferences:KeyData}">
            <TextBlock Text="{Binding Name}"/>
            <TextBlock Text="{Binding Count}"/>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</UserControl>

And set up a dependency property as below:

   internal class KeyData : DependencyObject
    {
        public string Name { get; set; }

        public int? Count
        {
            get { return (int?)GetValue(CountProperty); }
            set { SetValue(CountProperty, value); }
        }

        public static readonly DependencyProperty CountProperty =
             DependencyProperty.Register("Count",
                                         typeof(int?),
                                         typeof(KeyData),
                                         new FrameworkPropertyMetadata());
    }

And pass in a Data Context:

<UserControlName DataContext="{Binding Container.APresenter}"/>

However, the bindings are failing to locate the source...

System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=Removed; DataItem=null; target element is 'KeyData' (HashCode=4638229); target property is 'Count' (type 'Nullable`1')

I thought this was the point of a Dependency Property - to handle cases like this? Is anyone able to point out the part I've misunderstood?


Solution

  • The binding does not know who owns Count1 and Count2. Provide maybe an ElementName which refers to the object in question. Then possibly work off of its DataContext such as this binding:

    ="{Binding ElementName=PathBox, Path=DataContext.Count1}"
    

    I find that naming Xaml elements (even the page) then pathing to that named object into its internals or if it is a control via its datacontext solves most binding issues.

    Update

    Sometimes one has to x:reference to access named items. In that case depending on the object use x:name to name it then access it.

    ="{Binding Source={x:Reference PathBox} , Path=Count1}">