Listview Grouping Binding Question

ChasakisDChasakisD USMember ✭✭

Let's say we have the following classes and a grouping listview that binds to a Collection of ItemGrouped:

public class Item : BindableBase
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Description { get; set; }
}

public class ItemGrouped : ObservableCollection<Item>
{
    public string Title { get; set; }
    public bool IsActive { get; set; }
}

In XAML, inside the listview's ItemTemplate, how can i bind to an ItemGrouped Property instead of the default binding to the Item(e.g. i may want an extra feature when the itemgrouped.IsActive == true)?

Best Answer

  • ChasakisDChasakisD USMember ✭✭
    Accepted Answer

    I found a solution, but maybe there is a better approach. As in DataTemplateSelector in the OnSelectTemplate the item is typeof(Item), i search the item inside the ListView's ItemSource and get the ItemGrouped. Then i return the DataTemplate. My Selector is:

    public class ItemDataTemplateSelector : DataTemplateSelector
    {
        private readonly DataTemplate _activeDataTemplate;
        private readonly DataTemplate _inActiveDataTemplate;
    
        public PollDataTemplateSelector()
        {
            _activeDataTemplate = new DataTemplate(typeof(ActiveItemViewCell));
            _inActiveDataTemplate = new DataTemplate(typeof(InActiveItemViewCell));
        }
    
        protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
        {
            var itemModel = item as Item;
            var itemGroups = (container as ListView)?.ItemsSource as ObservableRangeCollection<ItemGrouped>;
    
            var itemGroup = FindItemInItemGroups(itemGroups, itemModel);
    
            if (itemGroup == null) return null;
    
            return itemGroup.IsActive ? _activeDataTemplate : _inActiveDataTemplate;
        }
    
        public ItemGrouped FindItemInItemGroups(IEnumerable<ItemGrouped> itemGroups, Item itemModel)
        {
            return (from itemGroup in itemGroups
                        from option in pollGroup
                            where itemModel != null && option.Id == itemModel.Id
                            select itemGroup).FirstOrDefault();
        }
    }
    

    Thanks to @LewisK

Answers

  • JulienRosenJulienRosen CAMember ✭✭✭✭

    cool question

    you could pass in a ItemGrouped reference to each Item and then bind directly to it

    curious if there is a more elegant solution

  • ChasakisDChasakisD USMember ✭✭

    Yeah that was what i thought, but i was interested in finding something more simple(like a trick with binding)

  • LewisKLewisK USUniversity ✭✭
    edited November 9

    You could use a reference, just reference it to the view with the binding context you want

    EG

    Blah = "{Binding Path=BindingContext.TestProperty, Source={x:Reference ElementId}}"

    Could pay to look at this page

    https://developer.xamarin.com/guides/xamarin-forms/xaml/xaml-basics/data_binding_basics/

  • JulienRosenJulienRosen CAMember ✭✭✭✭
    edited November 9

    @LewisK how do you create a reference to the group header?

  • ChasakisDChasakisD USMember ✭✭
    edited November 9

    @LewisK I tried

    {Binding Source={x:Reference GroupingListView}, Path=BindingContext.IsActive}
    

    but doesn't work.

    @JulienRosen In GroupHeaderTemplate just bind the GroupedProperty like {Binding Title}

    Edit: Correct me if i'm wrong, but a listview's BindingContext(if u don't override it) is the Page's BindingContext which is the ViewModel, right?

  • LewisKLewisK USUniversity ✭✭

    @ChasakisD said:
    @LewisK I tried

    {Binding Source={x:Reference GroupingListView}, Path=BindingContext.IsActive}
    

    but doesnt work.

    @JulienRosen In GroupHeaderTemplate just bind the GroupedProperty like {Binding Title}

    Ahh misread it a bit sorry. Could you use a datatemplate selector and bind the property for the children?

  • ChasakisDChasakisD USMember ✭✭

    @LewisK Sounds good. I'm gonna give it a try and give some feedback.

  • ChasakisDChasakisD USMember ✭✭
    Accepted Answer

    I found a solution, but maybe there is a better approach. As in DataTemplateSelector in the OnSelectTemplate the item is typeof(Item), i search the item inside the ListView's ItemSource and get the ItemGrouped. Then i return the DataTemplate. My Selector is:

    public class ItemDataTemplateSelector : DataTemplateSelector
    {
        private readonly DataTemplate _activeDataTemplate;
        private readonly DataTemplate _inActiveDataTemplate;
    
        public PollDataTemplateSelector()
        {
            _activeDataTemplate = new DataTemplate(typeof(ActiveItemViewCell));
            _inActiveDataTemplate = new DataTemplate(typeof(InActiveItemViewCell));
        }
    
        protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
        {
            var itemModel = item as Item;
            var itemGroups = (container as ListView)?.ItemsSource as ObservableRangeCollection<ItemGrouped>;
    
            var itemGroup = FindItemInItemGroups(itemGroups, itemModel);
    
            if (itemGroup == null) return null;
    
            return itemGroup.IsActive ? _activeDataTemplate : _inActiveDataTemplate;
        }
    
        public ItemGrouped FindItemInItemGroups(IEnumerable<ItemGrouped> itemGroups, Item itemModel)
        {
            return (from itemGroup in itemGroups
                        from option in pollGroup
                            where itemModel != null && option.Id == itemModel.Id
                            select itemGroup).FirstOrDefault();
        }
    }
    

    Thanks to @LewisK

Sign In or Register to comment.