XAML资源字典中的算术运算

时间:2018-10-03 02:21:45

标签: xaml xamarin.forms resourcedictionary ivalueconverter

我想做什么

我最近一直在探索XAML资源字典。它们非常强大,但是为了减少(甚至进一步减少)为适应任何修改而需要进行的更改,我想使用一些基本的算术运算来更改a的HeightRequest属性Entry

我已经在OnPlatform之类的不同方面很好地利用了OnIdiomFontSize

对于iOS平台,我想输入条目HeightRequest的{​​{1}}。 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> 的值,并为其添加一些数字。

我尝试过的

在另一种尝试中,I've found a converter并尝试使其适应我的用例。虽然没有智能感知或生成/编译错误,但应用程序在打开后立即崩溃。可以在上面的链接中找到ArithmeticConverter的.cs文件。

FontSize

我不完全理解转换器的用法,App.xaml值内的<?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> 对我来说也是新事物。查看转换器附带的示例,我想我是正确的 close ,可能只需要向正确的方向推?


是否可以单独(或使用转换器)在{Binding}中完成这种基本的算术函数?我希望在此文件中包含尽可能多的内容。

我在搜索中发现的其他解决方案都提到了使用viewmodel,但这是我想对每个平台/习惯用语每个条目应用的“全局”更改,因此我可以没有看到这种适应如何起作用。

感谢您的时间!

1 个答案:

答案 0 :(得分:4)

您的应用程序崩溃的原因之一是因为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(but this post contradicts it, may be they changed?

解决方案2

类似于解决方案1 ​​,但无需设置BindingContext,您可以在HeightRequest上使用具有默认值的OnIdiom。

<Setter Property="HeightRequest" Value="{OnIdiom Default=10, Converter={StaticResource AScript}, ConverterParameter={StaticResource StandardFontSize}}" />