Source for CompositeCollection: why can't I bind to the data context of another control, but should use CollectionViewSource?

In another question I recently asked , I was told to use CompositeCollection to access various sources for a ListBox .

The example uses an XmlDataProvider to provide some dummy data. I, however, have a view model that contains data.

It took me a while to bind my ListBox to view model data. I finally figured it out, but now I would like to understand why my previous approaches did not work.

The key to success was CollectionViewSource. My initial attempts:

 <CollectionContainer Collection="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.Movies}"/> <CollectionContainer Collection="{Binding ElementName=Window, Path=DataContext.Movies}"/> 

My idea was to find a Window that has the appropriate DataContext and bind it to the data. You can do this through FindAncestor or through ElementName , so I tried both. It seemed to me very logical, but, apparently, I was mistaken. When I launched the application, I did not see anything.
I also tried to link to another control that has a data context; e.g. StackPanel .

So, why don't I get data with FindAncestor and ElementName 1 but do I need to explicitly specify CollectionViewSource ?


This is where the code works.

 <StackPanel DockPanel.Dock="Top"> <ListBox ItemTemplateSelector="{StaticResource CustomDataTemplateSelector}"> <ListBox.Resources> <CollectionViewSource x:Key="ViewSource" Source="{Binding Movies}"/> </ListBox.Resources> <ListBox.ItemsSource> <CompositeCollection> <CollectionContainer Collection="{Binding Source={StaticResource ViewSource}}"/> <CollectionContainer Collection="{Binding Source={StaticResource MyButtonsData}}"/> </CompositeCollection> </ListBox.ItemsSource> <ListBox.ItemsPanel> <ItemsPanelTemplate> <WrapPanel IsItemsHost="True" Width="{Binding (FrameworkElement.ActualWidth), RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}"/> </ItemsPanelTemplate> </ListBox.ItemsPanel> </ListBox> </StackPanel> 

1 No, I did not forget to call this window and there was no typo.

+5
source share
1 answer

I found thread on microsoft.com discussing this issue.
This β€œmistake” seems to have been known for years, but has never been fixed.

The workaround I'm using ( CollectionViewSource ) is also suggested there.

Also, you really cannot use ElementName . I don’t know for what reason, but the workaround for ElementName uses x:Reference as suggested in another topic of the question .

 <CollectionContainer Collection="{Binding Source={x:Reference dummy}, Path=DataContext.Movies}"/> 

Interestingly, the XAML compiler will show an object reference not set to an instance of an object error during editing.
It is possible to compile and run, though if you are not using an ancestor type because you will get an XmlParseException due to a circular dependency.

To avoid a cyclic dependency error, you can put the CompositeCollection in resources and reference there via StaticResource. Then you can also use the type of ancestor.

 <ListBox.Resources> <CompositeCollection x:Key="CompositeCollection"> <CollectionContainer Collection="{Binding Source={x:Reference stackPanel}, Path=DataContext.Movies}"/> </CompositeCollection> </ListBox.Resources> <ListBox.ItemsSource> <CompositeCollection> <CollectionContainer Collection="{Binding Source={StaticResource CompositeCollection}}"/> </CompositeCollection> </ListBox.ItemsSource> 
+6
source

Source: https://habr.com/ru/post/1200874/


All Articles