Как связать разные свойства редактора с одной и той же переменной на основе платформы в Xamarin (XAML) - PullRequest
0 голосов
/ 16 октября 2019

Я пытаюсь привязать свойство PlainText (, которое является свойством TwoWay Bindable, которое я создал в своем CustomEditor ) CustomEditor, к переменной KeyString при iOS, исвяжите свойство Text с KeyString при Android.

Я знаю, что привязка PlainText к KeyString при iOS работает правильно (я проверял это), но привязка Text к KeyString для Androidзавершается с System.ArgumentNullException Value cannot be null. Parameter name: binding

Также IntelliSense подчеркивает части моего кода, которые используют BindingBase в x:TypeAgruments. Для первой части Intellisense говорит: PlainText does not support values of type OnPlatform(BindingBase), но код все еще работает, когда я запускаю его на моем iOS эмуляторе. Это дает мне ошибку Text does not support values of type OnPlatform(BindingBase) для Android обязательной части кода, и это часть моего XAML, которую он не может запустить.

Ниже приведен мой код XAML, любая идея, что яможет быть не так?

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

В моем классе редактора у меня есть этот код:

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

Ответы [ 2 ]

1 голос
/ 17 октября 2019

Поскольку мне не нравится работать с OnPlatform, я хотел бы предложить обходной путь, который я упомянул в комментарии.

В вас CustomEditor добавьте следующий код:

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

То, что я сделал, я просто переместил код OnPlatform в свой контроль, чтобы вы могли сохранить свой код xaml более чистым.

При таком подходе вы сможете использовать его как

<controls:CustomEditor HeightRequest="80" IsPassword="True" CustomTitle="{Binding KeyString}">
     <controls:CustomEditor.Effects>
         <controls:PasswordEffect/>
     </controls:CustomEditor.Effects>
</controls:CustomEditor>
1 голос
/ 17 октября 2019

x: TypeArguments OnPlatform представляет тип значения, которое вы собираетесь связать, в вашем случае KeyString имеет тип string. Взгляните на 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...