Mathieu Guindon
Mathieu Guindon

Reputation: 71227

TabControl w/DataGrid: Cannot find governing FrameworkElement or FrameworkContentElement for target element

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

Answers (2)

awgaya
awgaya

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

Mathieu Guindon
Mathieu Guindon

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:

Search Results tabbed toolwindow working as expected

Upvotes: 0

Related Questions