How to correctly change Binding via DataTrigger in Xamarin.Forms

I set the Binding in Entry.Text with two Triggers. Unfortunately, it does not work correctly. Changing the Binding from the first to the second (calling the second trigger), causes Entry.Text to be set to "". Of course, the source has been initialized correctly. It's like a problem between Trigger1 and Trigger2 calls - then this empty value appears in Entry.Text (instead of the expected Person.Surname).

Style

<Style TargetType="Entry" x:Key="MyStyle">
    <Style.Triggers>
        <DataTrigger TargetType="Entry" Binding="{Binding Source={x:Reference mySwitch}, Path=IsToggled}" Value="True">
            <Setter Property="Text">
                <Setter.Value>
                    <Binding Path="Surname" Mode="TwoWay" />
                </Setter.Value>
            </Setter>
        </DataTrigger>
        <DataTrigger TargetType="Entry" Binding="{Binding Source={x:Reference mySwitch}, Path=IsToggled}" Value="False">
            <Setter Property="Text">
                <Setter.Value>
                    <Binding Path="Name" Mode="TwoWay" />
                </Setter.Value>
            </Setter>
        </DataTrigger>
    </Style.Triggers>
</Style>

XAML

<Switch x:Name="mySwitch" />
<Entry Style="{StaticResource MyStyle}" />

Code Behind:

public partial class MainPage : ContentPage
{
    private Person p = new Person { Name = "Joe", Surname = "Doe" };
    public MainPage()
    {
        InitializeComponent();
        BindingContext = p;
    }
}

Source

public class Person : INotifyPropertyChanged
{
    private string _surname = "Doe";
    public string Surname
    {
        get => _surname;
        set
        {
            if (value != _surname)
            {
                _surname = value;
                Raise();
            }
        }
    }
    private string _name = "Joe";
    public string Name
    {
        get => _name;
        set
        {
            if (value != _name)
            {
                _name = value;
                Raise();
            }
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    private void Raise([CallerMemberName] string name = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

Does it also work incorrectly for you and how can you fix it?

Answers

  • ColeXColeX Member, Xamarin Team Xamurai
    edited November 2018

    Since Setter.Value is not a BindableProperty , so you can't make binding work on it .

    You have to hard code the value like this way

     <Style.Triggers>
            <DataTrigger TargetType="Entry" Binding="{Binding Source={x:Reference mySwitch}, Path=IsToggled}" Value="True">
                <Setter Property="Text" Value = "Doe"/>
            </DataTrigger>
            <DataTrigger TargetType="Entry" Binding="{Binding Source={x:Reference mySwitch}, Path=IsToggled}" Value="False">
                <Setter Property="Text" Value = "Joe"/>
            </DataTrigger>
        </Style.Triggers>
    

    Another workaround, you can create two Entry (one binding Name and the other binding SurName), show or hide them via Switch.IsToggled.

  • GaetanFGaetanF USMember ✭✭✭

    Setter.Value is not a BindableProperty however, it can contain a binding object.

    If you want to apply the binding through a DataTrigger , you can do something like this (assuming your switch is not toggled by default:

    Resource dictionary:

    <Binding x:Key="DefaultEntryBinding" Path="Name" Mode="TwoWay" />
    <Binding x:Key="ToggledEntryBinding" Path="Surname" Mode="TwoWay" />
    <Style x:Key="MyStyle" TargetType="Entry">
        <Setter Property="Text" Value="{StaticResource DefaultEntryBinding}" />
    
        <Style.Triggers>
            <DataTrigger TargetType="Entry"
                         Binding="{Binding Source={x:Reference mySwitch}, Path=IsToggled}"
                         Value="True">
                <Setter Property="Text" Value="{StaticResource ToggledEntryBinding}" />
            </DataTrigger>
        </Style.Triggers>
    </Style>
    

    Binding inside the dictionary are only there to avoid recreating a binding every time the switch is toggled. Be gentle to your GC, it will reward you.

Sign In or Register to comment.