-
Notifications
You must be signed in to change notification settings - Fork 1.9k
[Feature] Auto compiled binding on CollectionView's ItemTemplate, GroupHeaderTemplate and GroupFooterTemplate #8161
Description
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.