views:

174

answers:

2

Hello,

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

+2  A: 

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.

Philip Rieck
this: _docRepo.GetMaterialList() returns an ObservableCollection<Material>. Should I turn this into a IEnumerable? if yes then I loose the INotifyCollectionChanged when I want to add/delete material :/
Lisa
No, ObservableCollection is fine - it doesn't implement ICollectionView.
Philip Rieck
funny... I used ObservableCollection before but it did not work, now it works hm... prolly I still changed some resource stuff in the grouping.
Lisa
@Philip OK its nearly working... I have updated the thread with a further question! :)
Lisa
@Lisa I would break out your updates into a new question - binding a CollectionViewSource to a ICollectionView is a good question to stand on it's own (for great google power!), and combining the two is making it a bit hard to follow :) However, let me suggest an excellent article on debugging binding issues: http://bea.stollnitz.com/blog/?p=52
Philip Rieck
@Philip I know that link. But that does not help me understading, why SchoolclassCode can not be found on the collection...
Lisa
@Lisa The error seems to say that you are binding to a CollectionView rather than an item in that view - and the collection doesn't have a "SchoolclassCode" property. most likely your datacontext is not actually what you think it is.
Philip Rieck
Thats is what I thought too, but the binding to the ItemsSource works fine, no problem. I have only trouble with that binding to the TextBlock in the Expander: <Expander.Header><TextBlock Foreground="Black" Text="{Binding }"/> </Expander.Header> The binding to the ObservableCollection is fine, because the MaterialBrowserListViewModel is set as DataContext. I have studied many grouping samples on the net. All samples bind the same way I do and all have a binding on the TextBlock in the Expander to a property being a member of the ObservableCollection.
Lisa
A: 

For christ sake... why did nobody tell me that

the CollectionViewGroup.Name is a property of the collectionViewGroup and I HAVE to use it instead of my own value... now it works of course!

@Philipp for your help I gave you a point!

Lisa