如何在 XAML [Xamarin.Forms] 中使用 String 以外的类型设置自定义属性值

Posted

技术标签:

【中文标题】如何在 XAML [Xamarin.Forms] 中使用 String 以外的类型设置自定义属性值【英文标题】:How to set custom property value with Type other than String in XAML [Xamarin.Forms] 【发布时间】:2020-04-27 13:06:36 【问题描述】:

在 XAML 中的 Xamarin.Forms 中,您可以编写如下内容:

<Entry Keyboard="Plain" />

我发现了 Entry 类,Keyboard 属性的类型是 Xamarin.Forms.Keyboard。但是,如果我创建自己的自定义 ContentView 并在里面写这样的内容:

    public static readonly BindableProperty KeyboardProperty = BindableProperty.Create
    (
        propertyName: "Keyboard",
        returnType: typeof(Keyboard),
        declaringType: typeof(MyCustomContentView),
        defaultValue: Keyboard.Default,
        defaultBindingMode: BindingMode.TwoWay,
        propertyChanged: (bindable, oldValue, newValue) =>
        
            // some unrelated stuff here
        
    );
    public Keyboard Keyboard
    
        get => (Keyboard)GetValue(KeyboardProperty);
        set => SetValue(KeyboardProperty, value);
    

我不能为我自己的内容视图使用相同的 XAML 格式。显然它是一个简单的字符串,它期望Xamarin.Forms.Keyboard 类的实例。到目前为止,我发现它与KeyboardProperty 或绑定无关,而是Keyboard 属性本身(如果我是正确的)。我相信它与ValueConverters 有关,当 XAML 解析器到达这部分时,我必须定义某种形式的字符串到键盘的转换,只是似乎无法找到我需要做的答案。

【问题讨论】:

【参考方案1】:

Petzold 在他关于 Xamarin.Forms 的精美书中很好地解释了您的问题的答案(您可以免费下载 here!)。

第 7 章属性和属性部分的末尾,您可以阅读

...您可以在 XAML 中包含自定义类,这些类可以具有自定义类型的属性,或者这些属性可以是标准类型但允许附加值。您只需使用 C# TypeConverter 属性标记这些类型或属性,并提供派生自 TypeConverter 的类。

还有一些细节供好奇的人参考

(仅引用自上述书籍)

在那一章中,Petzold 通过给出一个带有标签的示例来说明这一点:

<Label Text="Hello from XAML!"        
       IsVisible="True"
       Opacity="0.75" 
       HorizontalTextAlignment="Center" 
       VerticalOptions="CenterAndExpand" 
       TextColor="Blue" 
       BackgroundColor="#FF8080" 
       FontSize="Large" 
       FontAttributes="Bold,Italic" /> 

然后继续解释 XAML 如何设置这些属性。

XAML 的简洁主要源于属性值的简洁性——例如,使用“Large”一词而不是调用 Device.GetNamedSize 方法。这些缩写未内置到 XAML 解析器中。 XAML 解析器由专门为此目的定义的各种转换器类来辅助。

当 XAML 解析器遇到 Label 元素时,它可以使用反射来确定 Xamarin.Forms 是否有一个名为 Label 的类,如果有,它可以实例化该类。现在它已准备好初始化该对象。 Text 属性是字符串类型,属性值只是分配给该属性。

Label 的 IsVisible 和 Opacity 属性分别是 bool 和 double 类型,它们和您想象的一样简单。 XAML 分析器使用 Boolean.Parse 和 Double.Parse 方法来转换属性值。 Boolean.Parse 方法不区分大小写,但通常布尔值在 XAML 中大写为“True”和“False”。 Double.Parse 方法传递了一个 CultureInfo.InvariantCulture 参数,因此转换不依赖于程序员或用户的本地文化。

Label 的Horizo​​ntalTextAlignment 属性是TextAlignment 类型,它是一个枚举。对于任何枚举类型的属性,XAML 解析器使用 Enum.Parse 方法将字符串转换为值。

VerticalOptions 属性属于 LayoutOptions 类型,一种结构。当 XAML 解析器使用反射引用 LayoutOptions 结构时,它发现该结构定义了 C# 属性:

[TypeConverter (typeof(LayoutOptionsConverter))] 
public struct LayoutOptions 
 
    … 

TypeConverter 属性由名为 TypeConverterAttribute 的类支持。 LayoutOptions 上的这个特定 TypeConverter 属性引用了一个名为 LayoutOptionsConverter 的类,该类派生自一个名为 TypeConverter 的公共抽象类,该类定义了名为 CanConvertFrom 和 ConvertFrom 的方法。当 XAML 分析器遇到此 TypeConverter 属性时,它会实例化 LayoutOptionsConverter。 XAML 中的 VerticalOptions 属性分配了字符串“Center”,因此 XAML 解析器将该“Center”字符串传递给 LayoutOptionsConverter 的 ConvertFrom 方法,并弹出一个 LayoutOptions 值。这被分配给 Label 对象的 VerticalOptions 属性。

【讨论】:

【参考方案2】:

完全回答问题。创建这个类:

using System;
using Xamarin.Forms;

public class KeyboardTypeConverter : TypeConverter

    public override bool CanConvertFrom(Type sourceType)
    
        return sourceType == typeof(string);
    

    public override object ConvertFromInvariantString(string value)
    
        switch (value)
        
            case "Chat": return Keyboard.Chat;
            case "Email": return Keyboard.Email;
            case "Numeric": return Keyboard.Numeric;
            case "Plain": return Keyboard.Plain;
            case "Telephone": case "Phone": return Keyboard.Telephone;
            case "Text": return Keyboard.Text;
            case "Url": return Keyboard.Url;
            default: return Keyboard.Default;
        
    

然后将TypeConverter 属性添加到Keyboard 属性:

using System.Reflection;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

[TypeConverter(typeof(KeyboardTypeConverter))]
public Keyboard Keyboard

    get => (Keyboard)GetValue(KeyboardProperty);
    set => SetValue(KeyboardProperty, value);

【讨论】:

以上是关于如何在 XAML [Xamarin.Forms] 中使用 String 以外的类型设置自定义属性值的主要内容,如果未能解决你的问题,请参考以下文章

如何根据 Xamarin.Forms xaml 中的本地化语言显示选取器项目

XAML中的Xamarin.Forms ListView AutoHeight

如何使用 xamarin.forms-shell 在 XAML 中动态绑定类型为 <ShellContent> 的 Tab.Items 列表

在 Xamarin.Forms 上的 XAML 中将 BindingContext 设置为 ViewModel

如何用xamarin.forms xaml

Xamarin.Forms 在 XAML 中使用局部变量