如何通过Xamarin.Forms中的DataTrigger正确更改绑定

时间:2018-11-21 12:20:00

标签: xamarin xamarin.forms

如果我使用“样式触发器”更改Entry.Text中的绑定,则第二个字段将被第一个绑定中的信息覆盖。换句话说,Person.Name被Person.Surname覆盖

您能重现此行为并告诉我如何改善它吗?

下面是完整的代码

样式定义

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

目标输入和切换:

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

隐藏代码:

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

来源:

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

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

在我看来,切换触发器时问题出在行为上,因为如果我从代码级别执行类似的测试,则不会发生这种现象。

下面的示例按预期工作:

测试类

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

自定义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}");
    }
}

来源

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

运行测试

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

结果(符合预期)

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 个答案:

答案 0 :(得分:0)

我认为发生这种情况的原因是,当您的Person类已初始化Name中的Data时,Surname为null,因此,直到将数据提供给他们时,这种奇怪的行为才会发生。

我建议您使用默认值(即string.Empty)定义Name和Surname属性,这将帮助您避免这样的事情:

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