CompositeCollection Binding Problem – It’s not part of the Visual Tree
XAML is fantastic, but occasionally unpredictable which can cause some confusion.
One instance of this is the CompositeCollection tag which is used to build up a collection of values from a number of sources.
An example of this might be as simple as adding a “Please choose…” to the top of a drop down list or more complex scenarios, such as building up a list of products from different suppliers. In most cases, when using MVVM these kind of situations can be handled in the View Model, but even so, it can still be useful to build up lists in the XAML.
One such example I hit recently was creating a context menu for filtering on a data grid. I wanted to filter based on the values in the column, but also add two sorting options at the top of the list. A simplified version of the XAML is shown in Listing 1 below.
<ContextMenu.ItemsSource> <CompositeCollection> <MenuItem Header="Sort Ascending" /> <MenuItem Header="Sort Descending" /> <Separator /> <CollectionContainer Collection="{Binding Path=FilterOptions}}" /> </CompositeCollection> </ContextMenu.ItemsSource>
Listing 1 – Simplified code to show an example usage of CompositeCollection
However if you try to use code such as this you’ll very quickly hit the following binding problem.
Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=FilterOptions; DataItem=null; target element is ‘CollectionContainer’ (HashCode=23627591); target property is ‘Collection’ (type ‘IEnumerable’)
Why? Well it is all down to the fact that the data context of the XAML, specified at the top level that is inherited down through the elements actually goes down the Visual Tree. The killer is that the CompositeCollection, having no visual properties, is not part of the visual tree and therefore does not inherit the data context. The CompositeCollection has no clue what “FilterOptions” is in this example and thus throws a binding error.
Luckily we can easily solve this as all elements have access to the static resources of the XAML so we can easily create a bridging static resource that does the binding that we need and then use that within the composite collection. Listing 2 shows the static resource that we need in this instance.
<Window.Resources> <CollectionViewSource x:Key="FilterOptionsBridge" Source="{Binding Path=Filters}" /> </Window.Resources>
Listing 2 – Static resource bridging back to the data context
And finally we can adjust our CollectionContainer to point to the static resource, as in Listing 3.
... <CollectionContainer Collection="{Binding Source={StaticResource FilterOptionsBridge}}" /> ...
Listing 3 – Update to reference the static resource
As a side note, the CollectionViewSource tag needs to bind to an IEnumerable, so if you are binding to a CollectionView or one of the derived classes you’ll need to change the binding to be to the SourceCollection property as shown in Listing 4.
<Window.Resources> <CollectionViewSource x:Key="FilterOptionsBridge" Source="{Binding Path=Filters.SourceCollection}" /> </Window.Resources>
Listing 4 – Updated binding to reference the SourceCollection
Here is my alternative approach:
http://blog.pmunin.com/2012/02/xaml-binding-to-compositecollection.html
You’ve completely missed the point of this post, based on the link you provide. This one is to solve the problem of binding an element which is not a part of the visual tree, not the limitations of the CompositeCollection.
-1 for the comment.
You absolute made my day with this post! IT SOLVED MY PROBLEM! Thanks!
This is what I’ve been looking for. Thanks a lot!
I’m working to solve this problem in a situation where the CompositeCollection is being implemented within a nested MenuItem defined by a style. The IEnumerable that would populate the CollectionContainer doesn’t have a resource I can refer to.
I encountered this exact problem in my first real WPF project. I searched all over for a solution, believing it to be a ContextMenu issue, and found lots of solutions that didn’t work in my case. I was all but ready to ditch WPF and resort to (tried and trusted) WinForms when a colleague found this article, and it has restored my faith in WPF! Thank you!