Reputation: 71227
I'm getting an annoying binding error that's basically my last roadblock with this control:
System.Windows.Data Error: 2 : Cannot find governing FrameworkElement or FrameworkContentElement for target element. BindingExpression:Path=SearchResults; DataItem=null; target element is 'CollectionViewSource' (HashCode=6017800); target property is 'Source' (type 'Object')
Here's the TabControl
's markup:
<TabControl ItemsSource="{Binding Tabs}" SelectedItem="{Binding SelectedTab}">
<TabControl.ItemTemplate>
<!-- tab header template works as intended -->
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate DataType="controls:SearchResultsViewModel">
<DataTemplate.Resources>
<CollectionViewSource x:Key="GroupedSearchResults"
Source="{Binding SearchResults}">
<CollectionViewSource.SortDescriptions>
<!-- sort descriptions -->
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.GroupDescriptions>
<!-- group descriptions -->
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</DataTemplate.Resources>
<controls:GroupingGrid ShowGroupingItemCount="True"
ItemsSource="{Binding Source={StaticResource GroupedSearchResults}}"
SelectedItem="{Binding SelectedItem}">
<DataGrid.Columns>
<!-- column definitions -->
</DataGrid.Columns>
</controls:GroupingGrid>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
The designer gives me no squiggly lines anywhere, which seems to indicate everything is ok; I only get the binding error at run-time, however the ViewModels (serach results) populate exactly as expected... they just don't bind into the CollectionViewSource
for some reason.
What am I doing wrong?
Upvotes: 1
Views: 458
Reputation: 21
Here's a workaround based on http://www.broculos.net/2014/04/wpf-how-to-bind-collectionviewsource.html. It works by introducing a StackPanel and moving the CollectionViewSource to the StackPanel resources:
<DataTemplate DataType="controls:SearchResultsViewModel">
<StackPanel>
<StackPanel.Resources>
<CollectionViewSource x:Name="ViewSource" x:Key="GroupedSearchResults" Source="{Binding Test}">
<CollectionViewSource.SortDescriptions>
<componentModel:SortDescription PropertyName="QualifiedMemberName.QualifiedModuleName.Name" />
</CollectionViewSource.SortDescriptions>
<CollectionViewSource.GroupDescriptions>
<PropertyGroupDescription PropertyName="QualifiedMemberName.QualifiedModuleName.Name" />
</CollectionViewSource.GroupDescriptions>
</CollectionViewSource>
</StackPanel.Resources>
<controls:GroupingGrid ShowGroupingItemCount="True" x:Name="TabGrid"
ItemsSource="{Binding Source={StaticResource GroupedSearchResults}}"
SelectedItem="{Binding SelectedItem}">
<DataGrid.Columns>
<DataGridTextColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=SearchResults_ModuleName}" Binding="{Binding QualifiedMemberName.QualifiedModuleName}" />
<DataGridTextColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=SearchResults_MemberName}" Binding="{Binding QualifiedMemberName.MemberName}" />
<DataGridTextColumn Header="{Resx ResxName=Rubberduck.UI.RubberduckUI, Key=SearchResults_Location}" Binding="{Binding Selection}" Width="*" />
</DataGrid.Columns>
</controls:GroupingGrid>
</StackPanel>
</DataTemplate>
Upvotes: 2
Reputation: 71227
No idea why an all-XAML solution can't work. I gave up and got it working by exposing a CollectionViewSource
member on the ViewModel:
public SearchResultsViewModel(string header, IEnumerable<SearchResultItem> searchResults)
{
_header = header;
_searchResults = new ObservableCollection<SearchResultItem>(searchResults);
_searchResultsSource = new CollectionViewSource();
_searchResultsSource.Source = _searchResults;
_searchResultsSource.GroupDescriptions.Add(new PropertyGroupDescription("QualifiedMemberName.QualifiedModuleName.Name"));
_searchResultsSource.SortDescriptions.Add(new SortDescription("QualifiedMemberName.QualifiedModuleName.Name", ListSortDirection.Ascending));
_closeCommand = new DelegateCommand(ExecuteCloseCommand);
}
// not really needed anymore
private readonly ObservableCollection<SearchResultItem> _searchResults;
public ObservableCollection<SearchResultItem> SearchResults { get { return _searchResults; } }
private readonly CollectionViewSource _searchResultsSource;
public CollectionViewSource SearchResultsSource { get { return _searchResultsSource; } }
Then in the XAML, I changed the GroupingGrid
's ItemsSource
binding to the View
member of the new SearchResultsSource
property, like this:
<controls:GroupingGrid ShowGroupingItemCount="True" x:Name="TabGrid"
ItemsSource="{Binding SearchResultsSource.View}"
SelectedItem="{Binding SelectedItem}">
And finally got my grid to populate:
Upvotes: 0