testing
testing

Reputation: 20279

How to update group header from ListView?

I'm removing items from my ListView. Because I also use a counter in the group header, I have to update it. But how can I do this? This is my code:

ListView:

<ListView x:Name="MyListList"
    HasUnevenRows="True" 
    CachingStrategy="RecycleElement" 
    IsGroupingEnabled="True" 
    GroupDisplayBinding="{Binding Key}" 
    IsPullToRefreshEnabled="True"
    RefreshCommand="{Binding LoadDataCommand}"
    IsRefreshing="{Binding IsRefreshing, Mode=OneWay}">

    <ListView.GroupHeaderTemplate>
        <DataTemplate>
            <customViews:MyGroupingHeaderCell/>
        </DataTemplate>
    </ListView.GroupHeaderTemplate>

    <ListView.ItemTemplate>
        <DataTemplate>
            <customViews:MyHeaderCell />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

Custom group header:

<?xml version="1.0" encoding="utf-8" ?>
<ViewCell xmlns="http://xamarin.com/schemas/2014/forms"
          xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
          x:Class="Views.MyGroupingHeaderCell"
          xmlns:customViews="clr-namespace:Views;"
          xmlns:renderer="clr-namespace:Common.CustomRenderers;">
    <renderer:ListViewGroupHeader x:Name="keyName" Style="{StaticResource labelHeader}" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" />
</ViewCell>
public partial class MyGroupingHeaderCell : ViewCell
{
    public MyGroupingHeaderCell()
    {
        InitializeComponent();
    }

    protected override void OnBindingContextChanged()
    {
        base.OnBindingContextChanged();
        var item = BindingContext as ObservableGroupCollection<string, CustomObject>;
        if (item != null)
        {
            this.keyName.Text = item.Key + " (" + item.Count + ")";
        }
        else
        {
            this.keyName.Text = string.Empty;
        }
    }
}

I create the Key for the item with this LINQ expression

List<ObservableGroupCollection<string, CustomObject>> resultList = rawList.OrderByWithDirection(order, descending)
                                                                            .GroupBy(group)
                                                                            .Select(p => new ObservableGroupCollection<string, CustomObject>(p))
                                                                            .OrderByWithDirection(i => i.Key, false) // sort the group
                                                                            .ToList();

where group is

Func<CustomObject, string> group = p => p.SomeObject.Identification;

Probable solution:

What I'm doing now is that I completely reload the ListView by removing the item from the origin data and re-setting the ItemSource. This is not a really perfomant solution, but it works. The advantage of an ObservableCollection is gone though.

Upvotes: 0

Views: 785

Answers (1)

Sharada
Sharada

Reputation: 13601

Assuming ObservableGroupCollection implements INotifyCollectionChanged - we can subscribe to collection change event. To do that it would be easier to add a bindable property as it is simpler to track property changes, and hence subscribe/unsubscribe from events.

public partial class MyGroupingHeaderCell : ViewCell
{
    public static readonly BindableProperty CollectionProperty =
        BindableProperty.Create(
            "Collection", typeof(INotifyCollectionChanged), typeof(MyGroupingHeaderCell),
            defaultValue: default(INotifyCollectionChanged), propertyChanged: OnCollectionChanged);

    public INotifyCollectionChanged Collection
    {
        get { return (INotifyCollectionChanged)GetValue(CollectionProperty); }
        set { SetValue(CollectionProperty, value); }
    }

    private static void OnCollectionChanged(BindableObject bindable, object oldValue, object newValue)
    {
        ((MyGroupingHeaderCell)bindable).OnCollectionChangedImpl((INotifyCollectionChanged)oldValue, (INotifyCollectionChanged)newValue);
    }

    protected virtual void OnCollectionChangedImpl(INotifyCollectionChanged oldValue, INotifyCollectionChanged newValue)
    {
        if(oldValue != null)
            oldValue.CollectionChanged -= OnCollectionChanged;
        if(newValue != null)
            newValue.CollectionChanged += OnCollectionChanged;

        OnCollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
    }

    void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
    {
        var item = BindingContext as ObservableGroupCollection<string, CustomObject>;
        if (item != null)
        {
            this.keyName.Text = item.Key + " (" + item.Count + ")";
        }
        else
        {
            this.keyName.Text = string.Empty;
        }
    }
}

And, XAML usage will change to:

<ListView.ItemTemplate>
    <DataTemplate>
        <customViews:MyHeaderCell Collection="{Binding}" />
    </DataTemplate>
</ListView.ItemTemplate>

Upvotes: 1

Related Questions