Search code examples
xamlbindingmauidatacontextcompiled-bindings

Binding data context changes when using vustom ContentView control


I have the following code:

<ListView ItemsSource="{Binding Creature.FriendlyEnvironment}"
          x:DataType="vm:PlantDetailsViewModel">
    <ListView.ItemTemplate>
        <DataTemplate>
            <ViewCell>
                <Label Text="{Binding Name}" x:DataType="m:Creature" />
                <!--<v:ListviewItemView Creature="{Binding .}" x:DataType="m:Creature" />-->
            </ViewCell>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

When I execute this code, the Label has the correct data context, and I can use the Create Name property. But if I want to use the commented out code, I got the following error:

'GardenerMaster.Views.ListviewItemView' cannot be converted to type 'GardenerMaster.Models.Creature'

Could you please help me, how can I pass the current item to my ListviewItemView?

ListviewItemView.xaml.cs

public partial class ListviewItemView : ContentView
{
    public static readonly BindableProperty CreatureProperty =
        BindableProperty.Create(propertyName: nameof(Creature), returnType: typeof(Creature), declaringType: typeof(ListviewItemView), defaultValue: default(Creature));

    public Creature Creature
    {
        get => (Creature)GetValue(CreatureProperty);
        set => SetValue(CreatureProperty, value);
    }

    public ListviewItemView()
    {
        InitializeComponent();
    }
}

ListviewItemView.xaml

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    x:Class="GardenerMaster.Views.ListviewItemView"
    x:DataType="v:ListviewItemView">
    <Label Text="{Binding Creature.Name}" />
</ContentView>

I tried various way to pass the current item, but none of them worked.

<v:ListviewItemView Creature="{Binding}" x:DataType="m:Creature" />
<v:ListviewItemView Creature="{Binding .}" x:DataType="m:Creature" />
<v:ListviewItemView Creature="{Binding Path=.}" x:DataType="m:Creature" />

I also tried to set the x:DataType="m:Creature" for the DataTemplate, but it did not work also.


Solution

  • You're seeing that error, because you're mixing up the different data types in the compiled bindings.

    You should declare the x:DataType on the DataTemplate:

    <DataTemplate x:DataType="m:Creature">
        <ViewCell>
            <v:ListviewItemView />
        </ViewCell>
    </DataTemplate>
    

    and make sure to use the same declaration on the ListviewItemView:

    <?xml version="1.0" encoding="UTF-8"?>
    <ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:m="clr-namespace:GardenerMaster.Models"
        x:Class="GardenerMaster.Views.ListviewItemView"
        x:DataType="m:Creature">
        <Label Text="{Binding Name}" />
    </ContentView>
    

    You also don't need the bindable property in the code-behind, that's redundant (to say the least):

    public partial class ListviewItemView : ContentView
    {
        public ListviewItemView()
        {
            InitializeComponent();
        }
    }
    

    The control inherits its BindingContext from the DataTemplate, so you can directly bind to Name instead of Creature.Name.