views:

61

answers:

1

I have a Binding in a inline style for the DataGridRowGroupHeader like this.

<sdk:DataGrid.RowGroupHeaderStyles>
     <Style TargetType="sdk:DataGridRowGroupHeader">
        <Setter Property="Template">
     <Setter.Value>
             <ControlTemplate TargetType="sdk:DataGridRowGroupHeader">
                           <TextBlock Margin="4,0,0,0" Text="{Binding Converter={StaticResource headerConverter}}" />

The DataGrid ItemsSource is Bound to a PageCollectionView containing an observable collection, which is grouped by a property in the collection. When I update the collection the rows of the grid change, but the binding in the GroupHeader does not change.

Is there a different way to bind this or a way to force the UI to update?

This is the converter I'm using on the Header binding:

 public class GroupHeaderConverter2 : IValueConverter {

public object Convert(object value, System.Type targetType, object parameter, CultureInfo culture) {
var cvg = value as CollectionViewGroup;

return string.Format("({0} Remaining)", cvg.Items.Count((i) => ((CheckListEventDefinition)i).Complete == false && ((CheckListEventDefinition)i).Required == true));
}

public object ConvertBack(object value,
        System.Type targetType,
        object parameter,
        CultureInfo culture) {
return null;
}

}

Got this to work by changing the source collection to my own extended ObservableCollection that also monitors the elements for PropertyChanged and then raises the CollectionChanged Event.

/// <summary> this collection is also monitoring the elements for changes so when PropertyChanged fires on any element, it will raise the CollectionChanged event</summary>
public class ObservableCollectionEx<T> : ObservableCollection<T> where T : INotifyPropertyChanged {

    public ObservableCollectionEx(ObservableCollection<T> regularCollection) {
        if (regularCollection != null) {
            foreach (var item in regularCollection) {
                this.Add(item);
            }
        }
    }

    public void RaiseCollectionChanged() {
        this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e) {
        Unsubscribe(e.OldItems);
        Subscribe(e.NewItems);
        base.OnCollectionChanged(e);
    }

    protected override void ClearItems() {
        foreach (T element in this)
            element.PropertyChanged -= handlePropertyChanged;

        base.ClearItems();
    }

    private void Subscribe(IList iList) {
        if (iList == null) return;
        foreach (T element in iList)
            element.PropertyChanged += handlePropertyChanged;
    }

    private void Unsubscribe(IList iList) {
        if (iList == null) return;
        foreach (T element in iList)
            element.PropertyChanged -= handlePropertyChanged;
    }

    private void handlePropertyChanged(object sender, PropertyChangedEventArgs e) {
        OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }
}
A: 

The problem is you are binding directly to the object and not to a property with a Path. If you bind without a Path the binding will never update because there is no PropertyChanged event to notify the UI that the binding has changed. The simplest change is to change your binding to {Binding Items, Converter={StaticResource headerConverter}} and then cast value in your converter directly to ReadOnlyObservableCollection<object>.

If you need more flexibility then this I believe you will have to implement your own ICollectionView with a custom CollectionViewGroup.

Stephan
Thanks for the idea, I actually got it to work though by switching the underlying collection to my own extended ObservableCollection that also monitors the elements it contains for PropertyChanged and then raises CollectionChanged.
Tom