What to assign to an x:DataType when using System.Linq.IGrouping

458 views Asked by At

Ok, this should be something simple, but I'm stuck.

I'm upgrading an old .Net Xamarin project and one of the things that I wanted to do is to add x:DataType tags to the XAML files, so that it can validate and autocomplete all bindings. E.g.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" 
             xmlns:vm="clr-namespace:MyProject.PageModels.Info"
             xmlns:models="clr-namespace:MyProject.Models"
             x:DataType="vm:InfoViewModel"
             x:Class="MyProject.Pages.Info.InfoPage"
             Title="PageTitle">

So far so good, but this particular page shows a grouped list of records, defined as:

public List<IGrouping<string, LocalDocument>> GroupedDocs { get; set; }

And now the compiler complains because I've not set a valid DataType to the ListView.GroupHeaderTemplate (because the bindings in the template do not exist in the ViewModel)... and I don't know what to assign to it, as it seems that x:DataType does not support Interfaces (and let's not even mention interfaces + generics).

    <ListView ItemsSource="{Binding GroupedDocs}" IsGroupingEnabled="true" 
                 Style="{StaticResource groupedList}" ItemTappedCommand="{Binding DocumentTappedCommand}">

        <ListView.GroupHeaderTemplate>
            <DataTemplate x:DataType="????"> <!-- <<<<< What to put here? -->
                <ViewCell Height="34">
                    <StackLayout Style="{StaticResource groupHeader}">
                        <Label Text="{Binding Key}"
                               Style="{StaticResource groupHeaderText}"/>
                    </StackLayout>
                </ViewCell>
            </DataTemplate>
        </ListView.GroupHeaderTemplate>

        <ListView.ItemTemplate>
            <DataTemplate x:DataType="models:LocalDocument">
                 <!-- (....) -->
            </DataTemplate>
        </ListView.ItemTemplate>

    </ListView>

What should I specify instead of ???? on the previous code example?

As a workaround, I've created a Dummy class that implements <IGrouping<string, Document> and assigned it as the x:DataType, but I don't really feel like that is a good solution. And, as I'm sure that many other projects will be using grouped lists, I'd be interested in knowing what the "best practice" would be for this case.

2

There are 2 answers

1
Wendy Zang - MSFT On BEST ANSWER

You could try to create your own Grouping.

public class Grouping<K, T> : ObservableCollection<T>
{
    public K Key { get; private set; }

    public Grouping(K key, IEnumerable<T> items)
    {
        Key = key;
        foreach (var item in items)
            this.Items.Add(item);
    }
}

Usage:

 public ObservableCollection<Grouping<string, LocalDocument>> GroupedDocs { get; set; }

Download the source file from the link below. https://github.com/jamesmontemagno/Xamarin.Forms-Monkeys

0
StudentNumber9 On

Set the data type on the group header template as null: x:DataType="{x:Null}"

This will override the page level data type and bypass XAML compilation error about the binding on Key. Hovering over Key still indicates "Member not found in data context" but it compiles fine, and grouping works as expected (Syncfusion listview in my case but generic listview should work the same way).