Home > Mobile >  Databinding a custom control does not work
Databinding a custom control does not work

Time:09-15

I have created a custom component with custom propertys. The Problem is that when I try to Bind something to the component by using it it will not compile and an error is thrown.

Error:

[XFC0009] No property, BindableProperty, or event found for "Label", or mismatching type between value and property.

Component 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"
             xmlns:viewmodel="clr-namespace:TestProject.Components"
             x:DataType="viewmodel:Tile"
             x:Class="TestProject.Components.Tile">

    <Frame CornerRadius="10"
           WidthRequest="300"
           HeightRequest="150">
        <Frame.GestureRecognizers>
            <TapGestureRecognizer Tapped="TileClicked"/>
        </Frame.GestureRecognizers>
        <StackLayout x:Name="SL_Content"
                     HorizontalOptions="Start"
                     VerticalOptions="Start">
            <Label Text="{Binding Label}" 
                   FontSize="{Binding Size}" 
                   FontAttributes="Bold"/>
            <Image Source="{Binding Icon}"
                   HorizontalOptions="Start"
                   WidthRequest="50"
                   HeightRequest="0"
                   Margin="0,10,0,0"
                   x:Name="I_Img"/>
        </StackLayout>
    </Frame>
</ContentView>

Lable property code which is not bindable:

private static readonly BindableProperty LabelProperty = BindableProperty.Create(
        propertyName: nameof(Label),
        returnType: typeof(string),
        defaultValue: string.Empty,
        declaringType: typeof(Tile),
        defaultBindingMode: BindingMode.OneWay);


public string Label
    {
        get => (string)GetValue(LabelProperty);
        set => SetValue(LabelProperty, value);
    }

Constructor:

public Tile()
{
    BindingContext = this;
    InitializeComponent();
}

Usage of the control:

<?xml version="1.0" encoding="utf-8"?>

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                    xmlns:components="clr-namespace:TestProject.Components"
                    xmlns:model="clr-namespace:TestProject.Model"
                    xmlns:viewmodel="clr-namespace:TestProject.ViewModel"
                    x:DataType="viewmodel:ScannedItemViewModel"
                    x:Class="TestProject.Pages.Popups.CodeDetected">
  
    <CollectionView ItemsSource="{Binding _scannedItems}">
        <CollectionView.ItemTemplate>
            <DataTemplate x:DataType="model:ScannedItem">
                <SwipeView>
                    <SwipeView.RightItems>
                        <SwipeItem Text="Delete"
                                   Invoked="SwipeItem_OnDelete"/>
                    </SwipeView.RightItems>
                    <HorizontalStackLayout HeightRequest="40">
                        <Label VerticalOptions="Center" HorizontalOptions="Start" WidthRequest="120"
                               Padding="15,0,0,0" FontSize="16" Text="{Binding _num}" />
                        <Label VerticalOptions="Center" HorizontalOptions="Start" FontSize="16"
                               Text="{Binding _serial}" />

Cannot bind something to Lable like this then the Error will be thrown

                        <components:Tile Label="{Binding _serial}"/>
                </HorizontalStackLayout>
            </SwipeView>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

CodePudding user response:

Usually, it makes a lot of sense to just tell your View that it needs to look for the bindings in itself:

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:viewmodel="clr-namespace:TestProject.Components"
         x:DataType="viewmodel:Tile"
         x:Name"this"
         x:Class="TestProject.Components.Tile">

And then change the binding like so:

<Label Text="{Binding Label}" 
                   FontSize="{Binding Size, Source={x:Reference this}}" 
                   FontAttributes="Bold"/>
            <Image Source="{Binding Icon, Source={x:Reference this}}"
                   HorizontalOptions="Start"
                   WidthRequest="50"
                   HeightRequest="0"
                   Margin="0,10,0,0"
                   x:Name="I_Img"/>

Also, BindingContext this in a custom control is always a mistake it messes with your controls VM assignment when you use it in views so change your constructor to

public Tile()
{
  InitializeComponent();
}

Good luck!

CodePudding user response:

You just need to change the private to the public, such as:

public static readonly BindableProperty LabelProperty = BindableProperty.Create(
    propertyName: nameof(Label),
    returnType: typeof(string),
    defaultValue: string.Empty,
    declaringType: typeof(Tile),
    defaultBindingMode: BindingMode.OneWay);

I had met this problem and in the official document, it is also public.

  • Related