0
votes

If I change the Binding in Entry.Text using "Style Trigger", the second field is overwritten with the information from the first Binding. In other words, Person.Name is overwritten by Person.Surname

Can you reproduce this behaviour and tell me how can I improve it?

Below is the complete code

Style definition

<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>

Target Entry and Switch:

<Label Text="Actual Person.Name" Grid.Row="0" Grid.Column="0" />
<Label  Text="{Binding Path=Name}" Grid.Row="0" Grid.Column="1" />
<Label Text="Actual Person.Surname" Grid.Row="1" Grid.Column="0" />
<Label  Text="{Binding Path=Surname}" Grid.Row="1" Grid.Column="1" />
<Label Text="Person.Name / Person.Surname" Grid.Row="2" Grid.Column="0" />
<Switch x:Name="mySwitch" Grid.Row="2" Grid.Column="1" />
<Label Text="Change Name/Surname" Grid.Row="3" Grid.Column="0" />
<Entry  Style="{StaticResource MyStyle}" Grid.Row="3" Grid.Column="1" />

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));
    }
}

---------------------------------------------------------------------------

It seems to me that the problem is with behavior when switching Triggers, because this phenomenon does not occur if I perform a similar test from the code level.

The following example works as expected:

Test Class

public class Test
{
    public void Run1()
    {
        Person p = new Person { Name = "Joe", Surname = "Doe" };
        Bindable bindable = new Bindable();
        Binding bindingToName = new Binding("Name");
        Binding bindingToSurname = new Binding("Surname");

        bindable.BindingContext = p;

        bindable.SetBinding(Bindable.TextProperty, bindingToName);
        bindable.SetBinding(Bindable.TextProperty, bindingToSurname);
        bindable.SetBinding(Bindable.TextProperty, bindingToName);
        bindable.SetBinding(Bindable.TextProperty, bindingToSurname);
        bindable.SetBinding(Bindable.TextProperty, bindingToName);
        bindable.SetBinding(Bindable.TextProperty, bindingToSurname);
    }
}

Custom BindableObject

public class Bindable : BindableObject
{
    public static readonly BindableProperty TextProperty = BindableProperty.Create("Text", typeof(string), typeof(Bindable), "", propertyChanged: MyPropertyChanged);       
    private static void MyPropertyChanged(BindableObject bindable, object oldValue, object newValue)
    {
        Debug.WriteLine($"Property changed from '{oldValue}' to {newValue}");
    }
}

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));
    }
}

Run Test

internal class Program
{
    private static void Main(string[] args)
    {
        new Test().Run1();
        Console.ReadKey();
    }
}

Result (as expected)

Property changed from '' to Joe
Property changed from 'Joe' to Doe
Property changed from 'Doe' to Joe
Property changed from 'Joe' to Doe
Property changed from 'Doe' to Joe
Property changed from 'Joe' to Doe
1
I have no idea why this is happening, but this problem occurs between Triggers. I struggle with this problem in many ways and I can not fix it, will you help me? - g_m

1 Answers

0
votes

The reason I think this is happening is that when your Person class has initialized the Data in Name an Surname is null and hence until the data is provided to them this weird behaviour will happen.

My suggestion to you would define the Name and Surname properties with a default value i.e. string.Empty which will help you avoid this something like this:

public class Person
{
   public string Name{get;set;} = string.Empty;
   public string Surname{get;set;} = string.Empty;
}