Внедрить систему как OnPlatform / OnIdiom - PullRequest
2 голосов
/ 15 января 2020

Мне нужно привязать к другому свойству в зависимости от языка моего приложения. Я хотел бы сделать это по XAML и был вдохновлен OnPlatform / OnIdiom.

Так что я создал что-то вроде OnIdiom, но для языков, но я понятия не имею, как чтобы сделать его доступным для любого контента в XAML .

using ThibertApp.Resources;

namespace ThibertApp.Localization
{
    public class OnLanguage<T>
    {
        T _EN;
        T _FR;
        bool _isENSet;
        bool _isFRSet;

        public T EN
        {
            get => _EN;
            set
            {
                _EN = value;
                _isENSet = true;
            }
        }

        public T FR
        {
            get => _FR;
            set
            {
                _FR = value;
                _isFRSet = true;
            }
        }

        public static implicit operator T(OnLanguage<T> onLanguage)
        {
            switch (AppResources.Culture.TwoLetterISOLanguageName)
            {
                default:
                case "en":
                    return onLanguage._isENSet ? onLanguage.EN : default(T);
                case "fr":
                    return onLanguage._isFRSet ? onLanguage.FR : default(T);
            }
        }
    }
}
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:s="clr-namespace:ThibertApp.Resources"
             xmlns:l="clr-namespace:ThibertApp.Localization;assembly=ThibertApp"
             x:Class="ThibertApp.Pages.HomePage"
             Title="{Binding Title}"
             IconImageSource="{Binding IconImageSource}"
             BackgroundColor="White"
             Style="{StaticResource ThibertPage}">
    <ContentPage.Content>
        <StackLayout Margin="10">
            <Frame CornerRadius="10"
                   BackgroundColor="{StaticResource ThibertGrey}">
                <Entry Placeholder="{Static s:AppResources.SearchPlaceholder}">
                    <Entry.Text>
                        <l:OnLanguage EN="{Binding TextEN}" FR="{Binding TextFR}"/>
                    </Entry.Text>
                </Entry>
            </Frame>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

Когда я ссылаюсь на свой класс и пытаюсь ввести значения, он выдает эти ошибки.

Код серьезности Описание Ошибка состояния подавления строки файла проекта XLS0504 Свойство «Текст» не поддерживает значения типа «OnLanguage». ThibertApp HomePage.xaml 17

и

Код серьезности Описание Состояние подавления строки файла проекта Положение ошибки 17:26. Тип l: OnLanguage не найден в пространстве имен xmlns clr: ThibertApp.Localization ThibertApp C: \ Users \ william_d \ source \ repos \ ThibertApp \ ThibertApp \ ThibertApp \ Pages \ HomePage.xaml 17

У кого-нибудь есть какое-либо руководство относительно того, как сделать это возможным? Я клонировал Xamarin.Forms и искал ссылку на OnIdiom / OnPlatform и не нашел ничего, что могло бы ответить на мои вопросы.

Большое спасибо

РЕДАКТИРОВАТЬ

С ответом Deczaloth я смог придумать расширение разметки, например:

    public class OnLanguage : BindableObject, IMarkupExtension<string>
    {
        public readonly static BindableProperty ENProperty = BindableProperty.Create(nameof(EN), typeof(string), typeof(OnLanguage));
        public string EN
        {
            get => GetValue(ENProperty) as string;
            set => SetValue(ENProperty, value);
        }

        public readonly static BindableProperty FRProperty = BindableProperty.Create(nameof(FR), typeof(string), typeof(OnLanguage));
        public string FR
        {
            get => GetValue(FRProperty) as string;
            set => SetValue(FRProperty, value);
        }

        public string ProvideValue(IServiceProvider serviceProvider)
        {
            SetBinding(BindingContextProperty, new Binding("BindingContext", source: (serviceProvider.GetService<IProvideValueTarget>() as IProvideValueTarget).TargetObject as BindableObject));
            return LanguageManager.LocalizedObject(EN, FR);
        }

        object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
        {
            return (this as IMarkupExtension<string>).ProvideValue(serviceProvider);
        }
    }

Вот как я реализую его в XAML:

                                        <Label TextColor="{StaticResource SecondaryTextColor}">
                                            <Label.Text>
                                                <other:OnLanguage EN="{Binding DescriptionEN}"
                                                                  FR="{Binding DescriptionFR}"/>
                                            </Label.Text>
                                        </Label>

Мой OnLanguage BindableObject не получает автоматически BindingContext. Я реализовал это вручную, но как мне сделать так, чтобы значение передавалось родителю при изменении BindingContext?

Ответы [ 2 ]

3 голосов
/ 15 января 2020

Возможно, вы говорите о Расширения разметки .

Вам нужно, чтобы ваш класс OnLanguage наследовал от IMarkupExtension как

public class OnLanguage<T> : IMarkupExtension<T>

Пожалуйста, обратитесь к следующему сообщению в блоге:

https://xamgirl.com/xaml-markup-extension-in-xamarin-forms/

1 голос
/ 24 января 2020

Решение, которое я нашел для этого, больше похоже на обходной путь, но работает очень хорошо.

Сложность состояла в том, чтобы создать две привязки, но привязать только одну к свойству объекта.

Вот что мой последний MarkupExtension выглядит так:

    public class OnLanguage : BindableObject, IMarkupExtension<Binding>
    {
        public readonly static BindableProperty ENProperty = BindableProperty.Create(nameof(EN), typeof(string), typeof(OnLanguage));
        public string EN
        {
            get => GetValue(ENProperty) as string;
            set => SetValue(ENProperty, value);
        }

        public readonly static BindableProperty FRProperty = BindableProperty.Create(nameof(FR), typeof(string), typeof(OnLanguage));
        public string FR
        {
            get => GetValue(FRProperty) as string;
            set => SetValue(FRProperty, value);
        }

        public Binding ProvideValue(IServiceProvider serviceProvider)
        {
            return new Binding(LanguageManager.LocalizedObject(EN, FR));
        }

        object IMarkupExtension.ProvideValue(IServiceProvider serviceProvider)
        {
            return (this as IMarkupExtension<Binding>).ProvideValue(serviceProvider);
        }

        protected override void OnBindingContextChanged()
        {
            base.OnBindingContextChanged();
        }
    }

И реализация:

                                        <Label TextColor="{StaticResource SecondaryTextColor}"
                                               x:Name="L">
                                            <Label.Text>
                                                <other:OnLanguage EN="DescriptionEN"
                                                                  FR="DescriptionFR"/>
                                            </Label.Text>
                                        </Label>

Поскольку я хочу, чтобы мой MarkupExtension предоставлял Binding, чтобы родительский объект мог установить его в своем свойстве, но не может иметь BindableProperties типа Binding, мне нужно, чтобы они были строками, представляющими имя связываемого свойства. Не сильно отличается от написания {Binding DescriptionEN}. Единственное ограничение этого решения состоит в том, что невозможно установить источник, конвертер, режим и т. Д. c. Обязательства. Если у кого-то есть идеи о том, как реализовать это, я был бы очень признателен.

Полагаю, я мог бы добавить их в качестве свойств, но это просто переписало бы все свойства Binding.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...