Недавно я изучал словари ресурсов XAML. Они очень мощные, но для того, чтобы сократить (даже еще больше) изменения, которые потребуются для учета любых модификаций, я хотел бы использовать некоторые базовые арифметические операции для изменения свойства HeightRequestEntry.
Я уже хорошо использую OnPlatform и OnIdiom для разных аспектов, например FontSize.
Для платформы iOS я хотел бы сделать HeightRequest записи 20+(FontSize). FontSize уже настроен с помощью OnIdiom (для планшетов он немного увеличен).
В идеальном мире основная вещь, которую я пытаюсь сделать, может выглядеть примерно как
.
<Setter Property = "HeightRequest" Value = "{DynamicResource StandardFontSize}+10">
У меня есть решение работающий, если я использую комбинацию OnIdiom и OnPlatform.
<?xml version = "1.0" encoding = "utf-8" ?>
<Application xmlns = "http://xamarin.com/schemas/2014/forms"
xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml"
x:Class = "XamarinDesigner.App"
xmlns:local = "clr-namespace:XamarinDesigner"
>
<Application.Resources>
<ResourceDictionary>
<OnIdiom x:Key = "StandardFontSize" x:TypeArguments = "x:Double" Tablet = "22" Phone = "18"/>
<Style x:Key = "MyEntry" TargetType = "Entry">
<Setter Property = "FontSize" Value = "{DynamicResource StandardFontSize}"/>
<Setter Property = "HeightRequest">
<Setter.Value>
<OnIdiom x:TypeArguments = "x:Double">
<OnIdiom.Phone>
<OnPlatform x:TypeArguments = "x:Double" iOS = "30"/>
</OnIdiom.Phone>
<OnIdiom.Tablet>
<OnPlatform x:TypeArguments = "x:Double" iOS = "40"/>
</OnIdiom.Tablet>
</OnIdiom>
</Setter.Value>
</Setter>
<Setter Property = "VerticalOptions" Value = "Center"/>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
С помощью этого «решения» мне нужно явно указать значение и самому произвести расчеты. Пока это работает, я хотел бы иметь возможность выполнить простую арифметическую операцию, чтобы найти значение FontSize и добавить к нему некоторое число.
В другой попытке я сделал Я нашел конвертер и попытался адаптировать его к моему варианту использования. Хотя ошибок intellisense или сборки / компиляции нет, приложение вылетает сразу после открытия. Файл .cs для ArithmeticConverter можно найти по ссылке выше.
<?xml version = "1.0" encoding = "utf-8" ?>
<Application xmlns = "http://xamarin.com/schemas/2014/forms"
xmlns:x = "http://schemas.microsoft.com/winfx/2009/xaml"
x:Class = "XamarinDesigner.App"
xmlns:local = "clr-namespace:XamarinDesigner"
>
<Application.Resources>
<local:ArithmeticConverter x:Key = "AScript"/>
<ResourceDictionary>
<OnIdiom x:Key = "StandardFontSize" x:TypeArguments = "x:Double" Tablet = "22" Phone = "18"/>
<Style x:Key = "MyEntry" TargetType = "Entry">
<Setter Property = "FontSize" Value = "{DynamicResource StandardFontSize}"/>
<Setter Property = "HeightRequest" Value = "{Binding Converter = {StaticResource AScript},ConverterParameter=Int32.Parse(20+{DynamicResource StandardFontSize}}"/>
<Setter Property = "VerticalOptions" Value = "Center"/>
</Style>
</ResourceDictionary>
</Application.Resources>
</Application>
Я не совсем понимаю использование конвертеров, и {Binding} внутри значения в App.xaml тоже для меня в новинку. Глядя на пример, предоставленный с преобразователем, я думаю, что я близко, чтобы быть правильным, и может просто нужно толкнуть в правильном направлении?
Можно ли выполнять эту базовую арифметическую функцию только на App.xaml (или с помощью преобразователя)? Я надеюсь вместить в этот файл как можно больше.
В других решениях, которые я нашел в своем поиске, упоминалось использование модели просмотра, но это «глобальное» изменение, которое я хочу применить к записи каждый для каждой платформы / идиомы, поэтому я не вижу, как эта адаптация может работать.
Спасибо за ваше время!
Вот гораздо более чистое решение: привяжите напрямую к вашему StandardFontSize, а затем сделайте все необходимые вычисления внутри самого конвертера. Таким образом, вы избавляетесь от необходимости использовать как ConverterParameter, так и регулярные выражения.
Хм, это один из способов, которым я мог бы это сделать, но я думаю, что это немного сложно с моими вариантами использования / намерениями. Я эффективно пытаюсь настроить эквивалент CSS и стараюсь избегать привязки, где могу, поскольку я просматриваю существующее приложение, обновляющее стили (которое в настоящее время не использует словари ресурсов). Многие страницы уже имеют довольно сложные настройки привязки к другим классам и моделям. В любом случае, я поиграю с этой концепцией и посмотрю, что у меня получится! Спасибо за ваш ответ.
Я очень жду того, что вы придумаете. Пожалуйста, опубликуйте свое решение, как только оно у вас будет.





Одна из причин сбоя вашего приложения заключается в том, что Converter находится за пределами ResourceDictionary.
Решение 1
Связывание следует использовать только тогда, когда назначен BindingContext, поэтому вам необходимо назначить его в файле cs.
App.cs:
public App()
{
InitializeComponent();
BindingContext = new { EntryHeightRequest = 10 };
MainPage = ...
}
App.xaml:
<ResourceDictionary>
<local:ArithmeticConverter x:Key = "AScript"/>
<OnIdiom x:Key = "StandardFontSize" x:TypeArguments = "x:Double" Tablet = "22" Phone = "18"/>
<Style x:Key = "MyEntry" TargetType = "Entry">
<Setter Property = "FontSize" Value = "{DynamicResource StandardFontSize}" />
<Setter Property = "HeightRequest" Value = "{Binding EntryHeightRequest, Converter = {StaticResource AScript},ConverterParameter = "{StaticResource StandardFontSize}"/>
<Setter Property = "VerticalOptions" Value = "Center"/>
</Style>
</ResourceDictionary>
ArithmeticConverter.cs:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is int constant && parameter is OnIdiom<double> dynamicSize)
return constant + dynamicSize.GetValue();
return -1;
}
OnIdiomExtension:
public static T GetValue<T>(this OnIdiom<T> idiom)
{
switch(Device.Idiom)
{
case TargetIdiom.Phone:
return idiom.Phone;
case TargetIdiom.Desktop:
return idiom.Desktop;
case TargetIdiom.Tablet:
return idiom.Tablet;
case TargetIdiom.TV:
return idiom.TV;
case TargetIdiom.Watch:
return idiom.Watch;
default:
throw new NotSupportedException();
}
}
Остерегаться: когда я пытался, BindingContext передается в ResourceDictionary (а этот пост ему противоречит, может быть, они изменились?)
Решение 2
Подобно Решение 1, но вместо установки BindingContext вы можете использовать OnIdiom для HeightRequest со значением по умолчанию.
<Setter Property = "HeightRequest" Value = "{OnIdiom Default=10, Converter = {StaticResource AScript}, ConverterParameter = {StaticResource StandardFontSize}}" />
Даже если конвертер помещен в словарь ресурсов, он все равно выйдет из строя, потому что есть другие, более «серьезные» проблемы, о которых я упоминал в своем комментарии.
Если вы поместите точку останова внутри вашего конвертера, вы увидите, почему он дает сбой ... Во-первых, в отличие от примера, который вы связали, вы ни к чему не привязываетесь, поэтому ваш
valueв вашем конвертере будет нулевым . Кроме того, регулярное выражение, используемое в примере, скорее всего, вам не подойдет. И да, вы можете без проблем иметь все это внутри App.xaml.