简体   繁体   中英

How do I bind different properties of an Editor to the same variable based on the platform in Xamarin (XAML)

I am trying to bind the property PlainText ( which is a TwoWay Bindable property which I created in my CustomEditor ) of CustomEditor to the variable KeyString when on iOS , and bind the property Text to KeyString when on Android .

I know that the binding of PlainText to KeyString when on iOS works properly (I have tested to ensure this), however the binding of Text to KeyString for Android fails with System.ArgumentNullException Value cannot be null. Parameter name: binding Value cannot be null. Parameter name: binding

Also IntelliSense underlines the parts of my code that use BindingBase in x:TypeAgruments . For the first part Intellisense says: PlainText does not support values of type OnPlatform(BindingBase) , but the code still works when I run it on my iOS emulator. It gives me the error Text does not support values of type OnPlatform(BindingBase) for the Android binding part of the code and that is the part of my XAML which it fails to run.

Below is my XAML code, any idea what I might be doing wrong?

<Frame Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" BorderColor="Black" Margin="0" Padding="0">
     <controls:CustomEditor HeightRequest="80" IsPassword="True">
         <controls:CustomEditor.PlainText>
             <OnPlatform x:TypeArguments="BindingBase">
                 <On Platform="iOS" Value="{Binding KeyString}"/>
             </OnPlatform>
         </controls:CustomEditor.PlainText>

         <controls:CustomEditor.Text>
             <OnPlatform x:TypeArguments="BindingBase">
                 <On Platform="Android" Value="{Binding KeyString}"/>
             </OnPlatform>
         </controls:CustomEditor.Text>

         <controls:CustomEditor.Effects>
             <controls:PasswordEffect>
             </controls:PasswordEffect>
         </controls:CustomEditor.Effects>
     </controls:CustomEditor>
</Frame>

In my custom Editor class I have this code:

using System;
using System.Collections.Generic;
using System.Text;
using Xamarin.Forms;

namespace MyApp.CustomControls
{
    public class CustomEditor : Editor
    {
        public static readonly BindableProperty IsPasswordProperty =
         BindableProperty.Create(nameof(IsPassword), typeof(bool), typeof(CustomEditor), false);

        public static readonly BindableProperty PlainTextProperty =
            BindableProperty.Create(nameof(PlainText),
                typeof(string),
                typeof(CustomEditor),
                String.Empty,
                defaultBindingMode:BindingMode.TwoWay,
                propertyChanged:OnPlainTextChanged);

        public bool IsPassword
        {
            get { return (bool)GetValue(IsPasswordProperty); }
            set { SetValue(IsPasswordProperty, value); }
        }

        public string PlainText {
            get { return (string)GetValue(PlainTextProperty); }
            set { SetValue(PlainTextProperty, value); }
        }

        private static void OnPlainTextChanged(BindableObject bindable, object oldValue, object newValue)
        {
            var control = (CustomEditor)bindable;
            if (newValue != null)
            {
                control.PlainText = newValue.ToString();
            }
        }
    }
}

The x:TypeArguments of OnPlatform represents the type of Value that you are going to bind, in your case KeyString is of type string . Take a look at OnPlatform .

<Frame Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" BorderColor="Black" Margin="0" Padding="0">
     <controls:CustomEditor HeightRequest="80" IsPassword="True">
         <controls:CustomEditor.PlainText>
             <OnPlatform x:TypeArguments="{x:Type x:String}">
                 <On Platform="iOS" Value="{Binding KeyString}"/>
             </OnPlatform>
         </controls:CustomEditor.PlainText>

         <controls:CustomEditor.Text>
             <OnPlatform x:TypeArguments="{x:Type x:String}">
                 <On Platform="Android" Value="{Binding KeyString}"/>
             </OnPlatform>
         </controls:CustomEditor.Text>

         <controls:CustomEditor.Effects>
             <controls:PasswordEffect>
             </controls:PasswordEffect>
         </controls:CustomEditor.Effects>
     </controls:CustomEditor>
</Frame>

As I don't like working with OnPlatform , I'd like to propose a workaround that I've mentioned in the comment.

In you CustomEditor add the following code:

public static BindableProperty CustomTitleProperty = BindableProperty.Create(
    propertyName: nameof(CustomTitle),
    returnType: typeof(string),
    declaringType: typeof(CustomEditor),
    defaultValue: null);

public string CustomTitle
{
    get { return (string)GetValue(CustomTitleProperty); }
    set { SetValue(CustomTitleProperty, value); }
}

protected override void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
    base.OnPropertyChanged(propertyName);

    if(propertyName==CustomTitleProperty.PropertyName)
    {
        SetCustomTitle();
    }
}

private void SetCustomTitle()
{
    switch(Device.RuntimePlatform)
    {
        case Device.iOS:
            {
                PlainText = CustomTitle;
                return;
            }
        case Device.Android:
            {
                Text = CustomTitle;
                return;
            }
        default:
            {
                throw new NotSupportedException($"{Device.RuntimePlatform} not supported in {nameof(SetCustomTitle)}");
            }
    }
}

What I did there is I simply moved OnPlatform code to your control, so you can keep your xaml code cleaner.

With this approach you should be able to use it like

<controls:CustomEditor HeightRequest="80" IsPassword="True" CustomTitle="{Binding KeyString}">
     <controls:CustomEditor.Effects>
         <controls:PasswordEffect/>
     </controls:CustomEditor.Effects>
</controls:CustomEditor>

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