XAML资源字典中的算术运算

5

我想做什么

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

我已经很好地利用了OnPlatformOnIdiom来处理不同方面,比如FontSize

对于iOS平台,我想使输入框的HeightRequest20+(FontSize)。使用OnIdiom已经设置了FontSize(对于平板电脑略微增加)。

在完美的世界里,我尝试做的核心问题可能看起来像这样:
<Setter Property="HeightRequest" Value="{DynamicResource StandardFontSize}+10">

"有效"的解决方法

如果我使用OnIdiomOnPlatform的组合,则有一个有效的解决方案。

<?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的值,并将一些数字添加到它上面。

我尝试过的

在另一次尝试中,我找到了一个转换器并尝试将其适应我的用例。虽然没有智能提示或构建/编译错误,但应用程序在打开后立即崩溃。可以在上面链接的ArithmeticConverter.cs文件中找到。

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

我不完全理解转换器的使用,以及在App.xaml中值内部使用的{Binding}也是新的东西。通过转换器提供的示例,我认为我已经接近正确了,可能只需要一个正确的方向。


是否有可能仅在App.xaml中(或使用转换器)进行这种基本的算术功能?我希望尽可能地将所有内容都包含在此文件中。

在我的搜索中发现的其他解决方案提到了视图模型的使用,但这是我想要应用于每个平台/方言的“全局”更改,因此我无法看到该适应如何工作。

感谢您的时间!


如果您在转换器内设置断点,您将会看到它为什么会崩溃... 首先,与您链接的示例不同,您没有绑定任何内容,因此您的转换器中的“value”将为空。另外,示例中使用的正则表达式很可能不适合您的需求。是的,您可以在App.xaml中放置所有这些内容而不会出现问题。 - jsanalytics
2
这里有一个更加简洁的解决方案:直接绑定到你的 StandardFontSize,然后在转换器内部进行所需的数学计算。这样,你就可以消除对 ConverterParameter 和正则表达式的需要。 - jsanalytics
嗯,这是我可以采取的一种方式,但在我的用例/意图周围会有一些棘手的问题。我实际上正在尝试设置类似于CSS的等效物,并尽可能避免绑定,因为我正在更新样式(当前不使用资源字典)。许多页面已经具有与其他类和模型的复杂绑定设置。无论如何,我将尝试这个概念,看看我能想出什么!感谢您的回复。 - Bejasc
我非常期待看看你会想出什么。请在你完成后发布你的解决方案。 - jsanalytics
1个回答

4

你的应用程序崩溃的原因之一是Converter位于ResourceDictionary之外。

解决方案1

仅在分配了BindingContext时才应使用Binding,因此您需要在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,而是使用默认值的HeightRequest上的OnIdiom。

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

1
即使将转换器放置在资源字典中,它仍然会崩溃,因为还有其他更“严重”的问题,正如我在评论中提到的那样。 - jsanalytics

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接