bindingmauicustom-controls

How to bind from a VM to properties of inner controls of a custom control in .NET MAUI


I am trying to make a custom checkbox.

I created the dependency property IsChecked, but I cannot bind to it from a VM.

In the control I have

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit"
             x:Class="PaperScoreTracker.Controls.PaperCheckBox"
             x:Name="this">

    <HorizontalStackLayout BindingContext="{x:Reference this}">
        <CheckBox x:Name="Part_CheckBox"
                  IsChecked="{Binding IsChecked}"/>
        <Label FontSize="20"
               Text="{Binding Text}"/>
    </HorizontalStackLayout>
    
</ContentView>

and then in the code behind I have

public partial class PaperCheckBox : ContentView
{
    public static readonly BindableProperty IsCheckedProperty = BindableProperty.Create(nameof(IsChecked), typeof(bool), typeof(PaperCheckBox), false);
    public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(PaperCheckBox), string.Empty);

    public bool IsChecked
    {
        get => (bool)GetValue(IsCheckedProperty);
        set => SetValue(IsCheckedProperty, value);
    }

    public string Text
    {
        get => (string)GetValue(TextProperty);
        set => SetValue(TextProperty, value);
    }

    public PaperCheckBox()
    {
        InitializeComponent();
    }
}

In the actual page I have

<controls:PaperCheckBox Grid.Row="1" Grid.Column="0"
                        IsChecked="{Binding ReverseScoring}"
                        Text="Reverse scoring"/>

and I have a VM for this page with the ReverseScoring observable property.

The problem is that ReverseScoring in the VM does no change when I check the checkbox in the UI.

What's weird is that the setting of a constant value works. I did Text="Reverse scoring" and in the UI the text is correct.

I made another custom button and I did the same thing but with a property of type Command. That one works. The command is forwarded from the control to the VM. Just the simple properties are not.


Solution

  • The Bindable Propertie's Binding Mode needs to be set to TwoWay in order to propagate the changes to your viewmodel. Learn more...

    public static readonly BindableProperty IsCheckedProperty = BindableProperty.Create(
    nameof(IsChecked), 
    typeof(bool), 
    typeof(PaperCheckBox), 
    false,
    BindingMode.TwoWay);
    
    public static readonly BindableProperty TextProperty = BindableProperty.Create(
    nameof(Text), 
    typeof(string), 
    typeof(PaperCheckBox), 
    string.Empty,BindingMode.TwoWay);