Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF DataGrid Grouping does not show up due to binding error

I get this error message:

System.Windows.Data Error: 5 : Value produced by BindingExpression is not valid for target property.; Value='System.Windows.Data.ListCollectionView' BindingExpression:Path=MaterialList; DataItem='MaterialBrowserListViewModel' (HashCode=24964411); target element is 'CollectionViewSource' (HashCode=36518048); target property is 'Source' (type 'Object')

Below is the important Xaml + ViewModel code.

What is wrong with my binding?

VIEWMODEL:

public class MaterialBrowserListViewModel : ViewModelBase
    {
        private IDocumentRepository _docRepo;
        private ICollectionView _materialList;

        public MaterialBrowserListViewModel()
        {
            _docRepo= new DocumentRepository();


            MaterialList = CollectionViewSource.GetDefaultView(_docRepo.GetMaterialList());
            //_materialList.GroupDescriptions.Add(new PropertyGroupDescription("Schoolclasscode"));
        }

        public ICollectionView MaterialList
        {
            get { return _materialList; }
            set
            {
                _materialList = value;
                this.RaisePropertyChanged("MaterialList");
            }
        }
    }

VIEW:

    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <!--<ResourceDictionary Source="Themes\DataGrid.Generic.xaml"/>-->
            </ResourceDictionary.MergedDictionaries>

            <CollectionViewSource Source="{Binding MaterialList}"  x:Key="groupedView">
                <CollectionViewSource.GroupDescriptions>
                    <PropertyGroupDescription PropertyName="DocumentName"/>
                </CollectionViewSource.GroupDescriptions>
            </CollectionViewSource>            

            <!-- GroupHeaderStyle -->
            <Style x:Key="GroupHeaderStyle" TargetType="{x:Type GroupItem}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type GroupItem}">
                            <Expander IsExpanded="True" 
                                      Background="Blue"
                                      Foreground="White">
                                <Expander.Header>
                                    <TextBlock Text="{Binding Name.Name}"/>
                                </Expander.Header>
                                <ItemsPresenter />
                            </Expander>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ResourceDictionary>

    </UserControl.Resources>
    <Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10" Background="AliceBlue">
        <Grid.RowDefinitions>
            <RowDefinition Height="35" />
            <RowDefinition Height="25"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <StackPanel Margin="0,0,0,10" Grid.Row="0" Orientation="Horizontal">
            <Button Content="Open" />
            <Button Content="Delete" />
            <Button Content="Export" />
            <Button Content="Clear Filter" />
        </StackPanel>
        <Grid Grid.Row="1">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="{Binding ElementName=col0, Path=ActualWidth}" />
                <ColumnDefinition Width="{Binding ElementName=col1, Path=ActualWidth}" />
                <ColumnDefinition Width="{Binding ElementName=col2, Path=ActualWidth}" />
                <ColumnDefinition Width="{Binding ElementName=col3, Path=ActualWidth}" />
                <ColumnDefinition Width="{Binding ElementName=col4, Path=ActualWidth}" />
                <ColumnDefinition Width="{Binding ElementName=col5, Path=ActualWidth}" />
            </Grid.ColumnDefinitions>
            <DatePicker Grid.Column="0" />
            <TextBox Grid.Column="1" />
            <ComboBox Grid.Column="2" />
            <ComboBox Grid.Column="3" />
            <TextBox Grid.Column="4" />
        </Grid> 
        <DataGrid       
        CanUserAddRows="False"
        CanUserDeleteRows="False"     
        AutoGenerateColumns="False"
        ItemsSource="{Binding Source={StaticResource groupedView}}"        
        Grid.Column="0" 
        Grid.Row="2"
        Grid.ColumnSpan="15"
        x:Name="MaterialGrid"            
        IsSynchronizedWithCurrentItem="True"
        AlternatingRowBackground="AliceBlue"
        VirtualizingStackPanel.VirtualizationMode="Recycling"
        VirtualizingStackPanel.IsVirtualizing="True"
        HeadersVisibility="Column" 
        CanUserResizeColumns="True"
        CanUserSortColumns="True"
        IsReadOnly="True"
            >
            <DataGrid.GroupStyle>
                <GroupStyle ContainerStyle="{StaticResource GroupHeaderStyle}">
                    <GroupStyle.Panel>
                        <ItemsPanelTemplate>
                            <DataGridRowsPresenter/>
                        </ItemsPanelTemplate>
                    </GroupStyle.Panel>
                </GroupStyle>
            </DataGrid.GroupStyle>
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Schoolday}" x:Name="col0" Header="Date" />
                <DataGridTextColumn Binding="{Binding Period}" x:Name="col1" Header="Period" />
                <DataGridTextColumn Binding="{Binding SchoolclassCode}" x:Name="col2"  Header="Class code" />
                <DataGridTextColumn Binding="{Binding DocumentName}" x:Name="col3"  Header="Document name" />
                <DataGridTextColumn Binding="{Binding Keywords}" x:Name="col4"  Header="Keywords" />
                <DataGridTextColumn Binding="{Binding DocumentId}" x:Name="col5"  Header="Doc Id" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</UserControl>

Update: Why is the Binding not working for "Schoolclasscode" below?

Error: System.Windows.Data Error: 40 : BindingExpression path error: 'SchoolclassCode' property not found on 'object' ''CollectionViewGroupInternal' (HashCode=15576908)'. BindingExpression:Path=SchoolclassCode; DataItem='CollectionViewGroupInternal' (HashCode=15576908); target element is 'TextBlock' (Name=''); target property is 'Text' (type 'String')

<!-- GroupHeaderStyle -->
            <Style x:Key="GroupHeaderStyle" TargetType="{x:Type GroupItem}">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type GroupItem}">
                            <Expander IsExpanded="True" 
                                      Background="AliceBlue"
                                      Foreground="White">
                                <Expander.Header>
                                    <TextBlock Text="{Binding SchoolclassCode}"/>
                                </Expander.Header>
                                <ItemsPresenter />
                            </Expander>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>

I have changed the binding now to the current datacontext to see whats in there:

  <DataGrid       
        CanUserAddRows="False"
        CanUserDeleteRows="False"     
        AutoGenerateColumns="False"
        ItemsSource="{Binding Source={StaticResource ResourceKey=groupedView}}"      
        Grid.Column="0" 
        Grid.Row="2"
        Grid.ColumnSpan="15"
        x:Name="MaterialGrid"            
        IsSynchronizedWithCurrentItem="True"
        AlternatingRowBackground="AliceBlue"
        VirtualizingStackPanel.VirtualizationMode="Recycling"
        VirtualizingStackPanel.IsVirtualizing="True"
        HeadersVisibility="Column" 
        CanUserResizeColumns="True"
        CanUserSortColumns="True"
        IsReadOnly="True"
            >
            <DataGrid.GroupStyle>
                <GroupStyle>
                    <GroupStyle.ContainerStyle>
                        <Style TargetType="{x:Type GroupItem}">
                            <Setter Property="Template">
                                <Setter.Value>
                                    <ControlTemplate TargetType="{x:Type GroupItem}">
                                        <Expander IsExpanded="True">
                                            <Expander.Header>
                                                <TextBlock Foreground="Black" Text="{Binding }"/>
                                            </Expander.Header>
                                            <ItemsPresenter />
                                        </Expander>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                        </Style>
                    </GroupStyle.ContainerStyle>
                </GroupStyle>
            </DataGrid.GroupStyle>
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Schoolday}" x:Name="col0" Header="Date" />
                <DataGridTextColumn Binding="{Binding Period}" x:Name="col1" Header="Period" />
                <DataGridTextColumn Binding="{Binding SchoolclassCode}" x:Name="col2"  Header="Class code" />
                <DataGridTextColumn Binding="{Binding DocumentName}" x:Name="col3"  Header="Document name" />
                <DataGridTextColumn Binding="{Binding Keywords}" x:Name="col4" Width="*"  Header="Keywords" />
                <!--<DataGridTextColumn Binding="{Binding DocumentId}" x:Name="col5"  Header="Doc Id" />-->
            </DataGrid.Columns>
        </DataGrid>

Do you see the class name at the Expander Text ? How can I access my ObservableCollection from this point?

alt text

like image 243
Elisabeth Avatar asked Sep 29 '10 21:09

Elisabeth


2 Answers

First of all, I would have made this a comment on Elisa's resolution about CollectionViewGroup.Name - if I had points enough to do so. Got this error too on my first attempt to use grouping.

The population of this Name property, from the source property beneath, is set by the use of: _materialList.GroupDescriptions.Add(new PropertyGroupDescription("Schoolclasscode"));

(More than one PropertyGroupDescription added to one view causes additional group styles to be applied for each and their corresponding Name properties populated accordingly.)

To clarify the Elisa's resolution - just change the binding as below:

<Expander IsExpanded="True" Background="AliceBlue" Foreground="White">
    <Expander.Header>
        <TextBlock Text="{Binding Name}"/>
    </Expander.Header>
    <ItemsPresenter />
</Expander>

Hope this saves could save time for somebody else.

like image 69
Henrik Avatar answered Nov 08 '22 19:11

Henrik


A CollectionViewSource takes a collection and wraps it with an ICollectionView. However, You are binding directly to a ICollectionView, which it cannot wrap. Make your property in the model some raw collection type IEnumerable) and bind to it.

Here's the code to CollectionViewSource's IsSourceValid:

private static bool IsSourceValid(object o)
{
    if (((o != null) && !(o is IEnumerable)) && (!(o is IListSource) && !(o is DataSourceProvider)))
    {
        return false;
    }
    return !(o is ICollectionView);
}

You can see it specifically checks for a ICollectionView and disallows it. Even though ICollectionView is IEnumerable, it is still not allowed.

like image 2
Philip Rieck Avatar answered Nov 08 '22 19:11

Philip Rieck