简体   繁体   中英

How do I define two bindable properties which update each other in Xamarin.Forms?

I want to declare a BindableProperty which acts as a convenience property to another BindableProperty in Xamarin.Forms. Setting one will update the other. I won't give the full context and the actual types, but a very simple and understandable scenario would be as follows:

I have a view which defines a Number and a Numberp1 property. Number is bindable, while the Numberp1 property acts as the convenience property here.

//Definition
public class MyView : ContentView
{
    public static BindableProperty NumberProperty = BindableProperty.Create(nameof(Number), typeof(int), typeof(MyView));

    public int Number { get => (int)GetValue(NumberProperty); set => SetValue(NumberProperty, value); }

    public int Numberp1 { get => Number + 1; set => Number = value - 1; }
}

//Usage
<local:MyView Number="{Binding Number}"/>

Things go well until a customer discovers that Numberp1 isn't bindable and would like me to make it bindable.

<local:MyView Numberp1="{Binding Numberp1}"/>
//error : No property, bindable property, or event found for 'Numberp1', or mismatching type between value and property.

How would I make both of these properties bindable but make them update each other? I tried investigating using Converters but they seem to only be usable at the Binding, not the BindableProperty definition.

Things go well until a customer discovers that Numberp1 isn't bindable and would like me to make it bindable.

Please create another BindableProperty for Numberp1,the Placeholder for the BindableProperty 'Numberp1Property ' should always match the name without 'Property'.

   public static BindableProperty NumberProperty = BindableProperty.Create(nameof(Number), typeof(int), typeof(MyView11), null, propertyChanged: OnNumberChanged);

    private static void OnNumberChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var num = (MyView11)bindable;
        num.Number = (int)newValue;
    }

    public static BindableProperty NumberpProperty = BindableProperty.Create(nameof(Numberp), typeof(int), typeof(MyView11), null, propertyChanged: OnNumber1Changed);

    private static void OnNumber1Changed(BindableObject bindable, object oldValue, object newValue)
    {
        var num = (MyView11)bindable;
        num.Numberp = (int)newValue;
    }

    public int Number
    {
        get => (int)GetValue(NumberProperty);
        set => SetValue(NumberProperty, value);
    }

    public int Numberp
    {
        get => Number + 1;
        set => Number = value - 1;
    }

Adding propertyChanged event for BindableProperty.

They both have to be defined as BindableProperty. Unfortunately, you can't rely on the setter methods being called, because the runtime doesn't necessarily go through the setter, it can directly call SetValue, which updates the definitive source of the value for a BindableProperty.

However you can rely on the fact that BindableProperty does get you PropertyChanged notifications automatically for either of your linked properties.

So, first define both properties:

    public static BindableProperty Number1Property = BindableProperty.Create(nameof(Number1), typeof(int), typeof(MyView));
    public static BindableProperty Number2Property = BindableProperty.Create(nameof(Number2), typeof(int), typeof(MyView));
    public int Number1 { get => (int)GetValue(Number1Property); set => SetValue(Number1Property, value); }
    public int Number2 { get => (int)GetValue(Number2Property); set => SetValue(Number2Property, value); }

Then, in the constructor, listen for changes:

public MyView ()
{
    InitializeComponent();

    PropertyChanged += MyView_PropertyChanged;
}

And finally, make sure that changes to either one is propagated to the other, where Number2 = Number1 + 1:

    private void MyView_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        if (e.PropertyName == Number1Property.PropertyName)
        {
            if (Number1 + 1 != Number2)
                Number2 = Number1 + 1;
        }
        if (e.PropertyName == Number2Property.PropertyName)
        {
            if (Number1 + 1 != Number2)
                Number1 = Number2 - 1;
        }
    }

EDIT As noted by @Knoop, the OP wanted the values to be related, not exactly the same.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM