DataGrid binding not working in GroupItem style declaration
Asked Answered
C

1

5

I'm having some trouble getting a binding to work that is defined in the resouces section of my user control. The same binding seems to work later on in the xaml when I bind it to a column of the datagrid. It just won't display data when in the style declaration.

The error I get is

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

The below binding ReceivedDate is not resolving at runtime.

<UserControl.Resources>

    <!-- Grouped Items Header: Show the messages in a group. ex: date received -->
    <Style x:Key="GroupedItemsHeaderStyle" TargetType="{x:Type GroupItem}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type GroupItem}">
                    <Expander x:Name="exp" IsExpanded="True"
                              Background="LightGray"
                              Foreground="Black">
                        <Expander.Header>
                            <TextBlock Text="{Binding Path=ReceivedDate, Converter={StaticResource DateToSortGroupConverter}}" Foreground="Black"/>
                        </Expander.Header>
                        <ItemsPresenter/>
                    </Expander>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

</UserControl.Resources>

In the code-behind for this UserControl I'm setting the itemsList as follows.

    void MailController_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == "CurrentMailBoxContent")
        {
            var currentMailBox = ((App) Application.Current).MailController.CurrentMailBoxContent;
            var collection = new ListCollectionView(currentMailBox);

            collection.GroupDescriptions.Add(new PropertyGroupDescription("ReceivedDate"));
            ContentDataGrid.ItemsSource = collection;
        }
    }

CurrentMailBoxContent is an

ObservableCollection<MailMessage>;

and ReceivedDate is a property in the MailMessage class.

public class MailMessage : INotifyPropertyChanged
{
    #region Fields

    public event PropertyChangedEventHandler PropertyChanged;

    private DateTime _receivedDate;

    #endregion

    #region Constructor

    public MailMessage(){}

    #endregion

    #region Properties


    public DateTime ReceivedDate
    {
        get { return _receivedDate; }
        set
        {
            if (_receivedDate == value) return;
            _receivedDate = value;
            OnPropertyChanged("ReceivedDate");
        }
    }

    #endregion

    #region methods

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion
}

I've tried changing the path of the binding to /ReceivedDate.

The thing that confuses me is that the same binding works when declared elsewhere. Such as in the various column headers.

Cowslip answered 23/5, 2015 at 0:57 Comment(3)
The Expander.Header does not get one of your view models. Instead the header gets its own object that has 2 properties named Name and ItemCount. That is in fact some sort of limitation of the cool grouping Feature.Cheyney
Unbelievable. The example I followed used name and I didn't clue in because name was also the name of the property in that examples data model. Thank you gomi42. Please post your comment as an answer so I can give you credit.Cowslip
Yeah that MS example caught me out too. Just assumed Name and ItemCount were properties on the underlying item models - so frustrating after three hours of trying to solve this. I've even seen other tutorials on grouping make the same assumption, which clearly haven't tested that their code works!Illimani
C
13

The Expander.Header does not get one of your view models. Instead the header gets an object that inherits from CollectionViewGroup that has two properties named Name and ItemCount.

Cheyney answered 23/5, 2015 at 9:23 Comment(4)
I 'm using a CollectionViewSource for grouping in my datagrid. My Group header is a TextBox binded to that Name Property you mention. I'm getting an error cause i'm trying to edit this read-only property. Is there a way i can bind my textbox to the Name Property of my items in my ObservableCollection in my ViewModel instead of the CollectionViewSource ?Croquette
I'm not sure whether I understand what you want to achieve. ObservableCollection has also the Items properties that contains all items of that group. Items[0].Name will work in case there is at least one item.Cheyney
Thanks ! I used the Items[0].Name and it worked ;)Croquette
I would never use indexing in XAML, because in case of clearing the ItemSource, binding errors will occure.Redbreast

© 2022 - 2024 — McMap. All rights reserved.