4
votes

I have a PCL and I am using MVVM pattern. I am building a togglebutton, that toggles when the related property in the viewmodel is activated, with behaviors and triggers. This is my behavior

 public class ToggleBehavior : Behavior<View>
{
    TapGestureRecognizer tapRecognizer;

    public static readonly BindableProperty IsToggledProperty = BindableProperty.Create<ToggleBehavior, bool>(tb => tb.IsToggled, false);

    public bool IsToggled
    {
        set { SetValue(IsToggledProperty, value); }
        get { return (bool)GetValue(IsToggledProperty); }
    }
}

This is how I consume my behavior

                             <Button Text="AUTO" Style="{StaticResource SmallEllipseButton}" BackgroundColor="{StaticResource BackgroundColor}" cm:Message.Attach="Automatic($dataContext)">
                                 <Button.Behaviors>
                                  <local:ToggleBehavior x:Name="autoToggleBehavior" IsToggled="{Binding CurrentMode,Converter={StaticResource modeToBooleanConverter}, ConverterParameter=AUTO}"/>
                                </Button.Behaviors>
                                <Button.Triggers>
                                  <DataTrigger TargetType="Button" Binding="{Binding Source={x:Reference autoToggleBehavior},Path=IsToggled}" Value="False" >
                                    <Setter Property="BackgroundColor" Value="White"/>
                                    <Setter Property="BorderColor" Value="White"/>
                                    <Setter Property="TextColor" Value="Gray"/>
                                  </DataTrigger>
                                  <DataTrigger TargetType="Button" Binding="{Binding Source={x:Reference autoToggleBehavior},Path=IsToggled}" Value="True" >
                                    <Setter Property="BackgroundColor" Value="{StaticResource BackgroundColor}"/>
                                    <Setter Property="TextColor" Value="White"/>
                                  </DataTrigger>
                                </Button.Triggers>
                             </Button> 

The problem is that the property IsToggled is not binded correctly in this IsToggled="{Binding CurrentMode,Converter={StaticResource modeToBooleanConverter}, ConverterParameter=AUTO}"/> If I set it statically to true or false it works. The problem I think is that I can't bind dinamically this property. I use the same binding with the same converter in the same page for an IsVisible property and it works. If I put a breakpoint in the converter, the application doesn't break in it, but for the IsVisible property breaks.

2

2 Answers

2
votes

Using a Button might not be the best option as it already has a tap handler and assigning one to it would still not trigger the event. I don't know if this helps but I changed the control to a Label to get the below to work. Of course if the Button is bound to a command that modifies the view model then you don't need the tap handler in the behaviour at all.

XAML:

<?xml version="1.0" encoding="utf-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:BehTest" x:Class="BehTest.BehTestPage">

    <Label Text="AUTO" HorizontalOptions="Center" VerticalOptions="Center">
         <Label.Behaviors>
          <local:ToggleBehavior x:Name="autoToggleBehavior" IsToggled="{Binding Toggled, Mode=TwoWay}"/>
        </Label.Behaviors>
        <Label.Triggers>
          <DataTrigger TargetType="Label" Binding="{Binding Source={x:Reference autoToggleBehavior},Path=IsToggled}" Value="False" >
            <Setter Property="BackgroundColor" Value="White"/>
            <Setter Property="TextColor" Value="Gray"/>
          </DataTrigger>
          <DataTrigger TargetType="Label" Binding="{Binding Source={x:Reference autoToggleBehavior},Path=IsToggled}" Value="True" >
            <Setter Property="BackgroundColor" Value="Blue"/>
            <Setter Property="TextColor" Value="White"/>
          </DataTrigger>
        </Label.Triggers>
     </Label> 
</ContentPage>

Behaviour:

public class ToggleBehavior : Behavior<View>
{
    readonly TapGestureRecognizer tapRecognizer;

    public ToggleBehavior()
    {
        tapRecognizer = new TapGestureRecognizer
        {
            Command = new Command(() => this.IsToggled = !this.IsToggled)
        };
    }

    public static readonly BindableProperty IsToggledProperty = BindableProperty.Create<ToggleBehavior, bool>(tb => tb.IsToggled, false);

    public bool IsToggled
    {
        set { SetValue(IsToggledProperty, value); }
        get { return (bool)GetValue(IsToggledProperty); }
    }

    protected override void OnAttachedTo(View bindable)
    {
        base.OnAttachedTo(bindable);
        bindable.GestureRecognizers.Add(this.tapRecognizer);
    }

    protected override void OnDetachingFrom(View bindable)
    {
        base.OnDetachingFrom(bindable);
        bindable.GestureRecognizers.Remove(this.tapRecognizer);
    }

    protected override void OnAttachedTo(BindableObject bindable)
    {
        base.OnAttachedTo(bindable);
        this.BindingContext = bindable.BindingContext;
        bindable.BindingContextChanged += Bindable_BindingContextChanged;
    }

    protected override void OnDetachingFrom(BindableObject bindable)
    {
        base.OnDetachingFrom(bindable);
        this.BindingContext = null;
        bindable.BindingContextChanged -= Bindable_BindingContextChanged;
    }

    void Bindable_BindingContextChanged(object sender, EventArgs e)
    {
        var bobject = sender as BindableObject;

        this.BindingContext = bobject?.BindingContext;
    }
}
-1
votes

We added a ToggleButton into our NuGet! Its free to use.

xmlns:aw="clr-namespace:AscendantWare.Xamarin.Essentials.Controls"

<aw:AWToggleButton TextColor="White" ToggleBackgroundColor="DarkGoldenrod" Margin="0" VerticalOptions="FillAndExpand" HorizontalOptions="Fill" CornerRadius="15" IsToggled="{Binding IsNoteEnabled, Mode=TwoWay}" Command="{Binding MyCommand}"/>

More Informations in our online documentation here!