Skip to content

[Feature] Auto compiled binding on CollectionView's ItemTemplate, GroupHeaderTemplate and GroupFooterTemplate #8161

@yairp03

Description

@yairp03

Description

This feature determines automatically the DataType of a DataTemplate inside <CollectionView.ItemTemplate>, <CollectionView.GroupHeaderTemplate> and/or <CollectionView.GroupFooterTemplate>, without need of specifying x:DataType manually.
Also, it allows using an x:DataType on a page when there is Group Header/Footer Template that using group attributes.

Normal CollectionView

For example, I have this Monkey model:

public class Monkey
{
    public string Species { get; set; }
}

Inside the ViewModel, I have this list of monkeys:

public partial class MonkeysViewModel
{
    public List<Monkey> MonkeysList { get; } = new();
}

And in the page, I have a CollectionView with a binding to the MonkeysList:

<ContentPage x:DataType="viewmodel:MonkeysViewModel">
    <CollectionView ItemsSource="{Binding MonkeysList}">
    </CollectionView>
</ContentPage>

Currently, in order to use the ItemTemplate without getting any binding error, I need to specify the type of the item using x:DataType on the DataTemplate tag, like this:

<ContentPage x:DataType="viewmodel:MonkeysViewModel">
    <CollectionView ItemsSource="{Binding MonkeysList}">
        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="model:Monkey"> <!--Required in order to use the Species member-->
                <Label Text="{Binding Species}" />
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

Feature benefits

This feature will make the code cleaner, will enable doing the same thing without specifying the x:DataType, and will automatically determine that because the CollectionView's ItemSource is a Collection of Monkey's, then each item is a Monkey.

Grouped CollectionView

In a grouped CollectionView, the ItemSource needs to be an IEnumerable of IEnumerables.
For example:

public partial class MonkeysViewModel
{
    public List<List<Monkey>> MonkeysGroups { get; } = new();
}
<CollectionView IsGrouped="True" ItemsSource="{Binding MonkeysGroups}">
</CollectionView>

If we want to use <CollectionView.GroupHeaderTemplate> or <CollectionView.GroupFooterTemplate>, we can't use compiled binding on the page, because then it will require us to specify the x:DataType for the DataTemplate, which we can't do. For example:

<ContentPage x:DataType="viewmodel:MonkeysViewModel"> <!--Specifying x:DataType for page-->
    <CollectionView IsGrouped="True" ItemsSource="{Binding MonkeysList}">
        <CollectionView.GroupHeaderTemplate>
            <DataTemplate> <!--Can't use x:DataType, there's no syntax for List<Monkey> type-->
                <Label Text="{Binding Count}" /> <!--Will raise a 'member not found' error-->
            </DataTemplate>
        </CollectionView.GroupHeaderTemplate>
        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="model:Monkey">
                <Label Text="{Binding Species}" />
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

Feature benefits

Besides the code being cleaner, this feature will allow using compiled binding on a page that has a grouped CollectionView in it, that uses the group's header and/or footer templates.

Final code with the feature

<ContentPage x:DataType="viewmodel:MonkeysViewModel">
    <CollectionView IsGrouped="True" ItemsSource="{Binding MonkeysList}">
        <CollectionView.GroupHeaderTemplate>
            <DataTemplate> <!--No need for x:DataType, automatically determines the type is 'List<Monkey>'-->
                <Label Text="{Binding Count}" /> <!--Working, because 'List<Monkey>' has a 'Count' member-->
            </DataTemplate>
        </CollectionView.GroupHeaderTemplate>
        <CollectionView.ItemTemplate>
            <DataTemplate> <!--No need for x:DataType, automatically determines the type is 'Monkey'-->
                <Label Text="{Binding Species}" /> <!--Working, because 'Monkey' has a 'Species' member-->
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

Public API Changes

Code

The example will use this code:

public class Monkey
{
    public string Species { get; set; }
}
public partial class MonkeysViewModel
{
    public List<Monkey> MonkeysList { get; } = new();
    public List<List<Monkey>> MonkeysGroups { get; } = new();
}

Normal CollectionView

For a non-grouped CollectionView, the xaml code, instead of this:

<ContentPage x:DataType="viewmodel:MonkeysViewModel">
    <CollectionView ItemsSource="{Binding MonkeysList}">
        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="model:Monkey"> <!--Required in order to use the Species member-->
                <Label Text="{Binding Species}" />
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

Will look like this:

<ContentPage x:DataType="viewmodel:MonkeysViewModel">
    <CollectionView ItemsSource="{Binding MonkeysList}">
        <CollectionView.ItemTemplate>
            <DataTemplate> <!--No need for x:DataType-->
                <Label Text="{Binding Species}" /> <!--Working and has intellisense-->
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

Grouped CollectionView

For a grouped CollectionView, the xaml code, instead of this:

<ContentPage> <!--Can't use x:DataType, because using groups members-->
    <CollectionView IsGrouped="True" ItemsSource="{Binding MonkeysList}">
        <CollectionView.GroupHeaderTemplate>
            <DataTemplate> <!--Can't use x:DataType, there's no syntax for List<Monkey> type-->
                <Label Text="{Binding Count}" /> <!--'No DataContext found' and no intellisense-->
            </DataTemplate>
        </CollectionView.GroupHeaderTemplate>
        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="model:Monkey">
                <Label Text="{Binding Species}" />
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

Will look like this:

<ContentPage x:DataType="viewmodel:MonkeysViewModel"> <!--Specifying x:DataType-->
    <CollectionView IsGrouped="True" ItemsSource="{Binding MonkeysList}">
        <CollectionView.GroupHeaderTemplate>
            <DataTemplate> <!--No need for x:DataType-->
                <Label Text="{Binding Count}" /> <!--Working and has intellisense-->
            </DataTemplate>
        </CollectionView.GroupHeaderTemplate>
        <CollectionView.ItemTemplate>
            <DataTemplate> <!--No need for x:DataType-->
                <Label Text="{Binding Species}" /> <!--Working and has intellisense-->
            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentPage>

Intended Use-Case

The feature will be used on any page that has a CollectionView in it and will make the code cleaner.
Also, it will enable to use compiled bindings on the page, even if it has a grouped CollectionView that uses group members inside the group header and/or footer templates.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions