0

I'm having this problem with a custom view I made that connects a checkbox with a text and allows you to tap the entire view to tick the checkbox. But when I bind to the exposed binding from the checkbox It doesn't seem to react to changes. I'm clearly not understanding something and was hoping maybe someone here can see that obvious thing I am missing. A normal checkbox works just fine.

I looked at several of the solutions on site and tried a few of the things I found but alas, no dice.

xaml:

<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms" 
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Celery.Controls.CheckboxWithTextControl">
    <ContentView.Content>
        <Grid ColumnDefinitions="*,48">
            <Grid.GestureRecognizers>
                <TapGestureRecognizer Tapped="OnTapped"/>
            </Grid.GestureRecognizers>
            <Label x:Name="DisplayedLabel"
                   HorizontalTextAlignment="Start"
                   VerticalTextAlignment="Center"/>
            <CheckBox x:Name="DisplayedCheckbox"
                      Grid.Column="1"
                      HorizontalOptions="Center"
                      VerticalOptions="Center">
                <VisualStateManager.VisualStateGroups>
                    <VisualStateGroupList>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal">
                                <VisualState.Setters>
                                    <Setter Property="Color" Value="{StaticResource TextColour}"/>
                                </VisualState.Setters>
                            </VisualState>
                            <VisualState x:Name="IsChecked">
                                <VisualState.Setters>
                                    <Setter Property="Color" Value="{StaticResource SecondryTextColor}"/>
                                </VisualState.Setters>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateGroupList>
                </VisualStateManager.VisualStateGroups>
            </CheckBox>
        </Grid>
    </ContentView.Content>
</ContentView>

cs

using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace Celery.Controls
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class CheckboxWithTextControl : ContentView
    {
        public static readonly BindableProperty TextProperty = 
            BindableProperty.Create("Text", typeof(string), typeof(CheckboxWithTextControl),"Default", BindingMode.OneWay, 
                propertyChanged: (bindable, oldValue, newValue) =>
                {
                    if (newValue != null && bindable is CheckboxWithTextControl control)
                    {
                        control.DisplayedLabel.Text = (string)newValue;
                    }
                });


        public static readonly BindableProperty IsCheckedProperty =
            BindableProperty.Create("IsChecked", typeof(bool), typeof(CheckboxWithTextControl),false , BindingMode.TwoWay,
                propertyChanged: (BindableObject bindable, object oldValue, object newValue) =>
                {
                    if (newValue != null && bindable is CheckboxWithTextControl control)
                    {
                        control.DisplayedCheckbox.IsChecked = (bool)newValue;
                    }
                });
        public string Text
        {
            get { return (string)GetValue(TextProperty); }
            set { SetValue(TextProperty, value); }
        }

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

        public CheckboxWithTextControl()
        {
            InitializeComponent();
        }

        private void OnTapped(object sender, EventArgs e)
        {
            IsChecked = !IsChecked;
        }
    }
}

EDIT 1: I found out that if I tap the checkbox itself it breaks, but tapping anyother part of the screen works.

  • It Actually breaks it even more actually but thats because it is used inside a page, where the binding context is set to a view model. like so `` ` – BananaSupreme Jan 28 '21 at 23:49

2 Answers2

0

I changed the checkbox to also update the exposed bindable when it updates as such

private void OnCheckedChange(object sender, CheckedChangedEventArgs e)
        {
            if (IsChecked != e.Value) IsChecked = e.Value;
        }

and the checkbox is now

<CheckBox x:Name="DisplayedCheckbox"
                      Grid.Column="1"
                      HorizontalOptions="Center"
                      VerticalOptions="Center"
                      CheckedChanged="OnCheckedChange">
-1

But when I bind to the exposed binding from the checkbox It doesn't seem to react to changes.

I test you code, and there is one problem with Grid, please modify your code by following code:

 <ContentView.Content>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Grid.GestureRecognizers>
            <TapGestureRecognizer Tapped="OnTapped" />
        </Grid.GestureRecognizers>
        <Label
            x:Name="DisplayedLabel"
            Grid.Column="0"
            HorizontalTextAlignment="End"
            VerticalTextAlignment="Center" />
        <CheckBox
            x:Name="DisplayedCheckbox"
            Grid.Column="1"
            HorizontalOptions="StartAndExpand"
            VerticalOptions="Center">
            <VisualStateManager.VisualStateGroups>
                <VisualStateGroupList>
                    <VisualStateGroup x:Name="CommonStates">
                        <VisualState x:Name="Normal">
                            <VisualState.Setters>
                                <Setter Property="Color" Value="Gray" />
                            </VisualState.Setters>
                        </VisualState>
                        <VisualState x:Name="IsChecked">
                            <VisualState.Setters>
                                <Setter Property="Color" Value="Red" />
                            </VisualState.Setters>
                        </VisualState>
                    </VisualStateGroup>
                </VisualStateGroupList>
            </VisualStateManager.VisualStateGroups>
        </CheckBox>
    </Grid>
</ContentView.Content>

Then you use this custom control like this:

  <customcontrol:CheckboxWithTextControl IsChecked="{Binding property}" Text="text" />

Do you implement INotifyPropertyChanged to update property value?

 public partial class Page1 : ContentPage, INotifyPropertyChanged
{
   
    private bool _property;
    public bool property
    {
        get { return _property; }
        set
        {
            _property = value;
            RaisePropertyChanged("property");
        }
    }
    public Page1()
    {
        InitializeComponent();           
        property = true;
        this.BindingContext = this;
    }

  
    public event PropertyChangedEventHandler PropertyChanged;

    
    public void RaisePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
Cherry Bu - MSFT
  • 10,160
  • 1
  • 10
  • 16
  • As far as I can tell the only changes you made is to how things are placed in the grid, thats not the look I am trying to achieve... I did come to understand the binding fails only when I tap the checkbox itself, when I touch everything else it does work – BananaSupreme Jan 29 '21 at 10:07
  • @BananaSupreme According to your previous description, you did not point out the specific problem, so I can only try to use your code to restore your problem. But glad you solved your problem. – Cherry Bu - MSFT Feb 01 '21 at 01:43