Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set custom property value with Type other than String in XAML [Xamarin.Forms]

In Xamarin.Forms in XAML, you can write something like:

<Entry Keyboard="Plain" />

I scouted the Entry class and the Keyboard property is of type Xamarin.Forms.Keyboard. However, if I create my own custom ContentView and write something like this inside:

    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);
    }

I cannot use the same XAML format for my own content view. Obviously it is a simple string, where it is expecting an instance of the Xamarin.Forms.Keyboard class. So far I've figured out that it has nothing to do with the KeyboardProperty nor bindings, but the Keyboard property itself (if I'm correct). I believe it has something to do with ValueConverters, that I have to define some form of string to Keyboard conversion when the XAML parser gets to this part, just can't seem to find the answer what I need to do.

like image 716
Vlladz Avatar asked Mar 03 '23 23:03

Vlladz


1 Answers

The answer to your question is nicely explained by Petzold in his beautiful book about Xamarin.Forms (that you can download for free here!).

At the end of the section Properties and attributes in chapter 7 you can read

... you can include custom classes in XAML, and these classes can have properties of custom types, or the properties can be of standard types but allow additional values. All you need is to flag these types or properties with a C# TypeConverter attribute and provide a class that derives from TypeConverter.

And some detail for the curious

(simply quoted from the aforementioned book)

In that chapter Petzold illustrates this by given an example with a Label:

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

and then goes on explaining how those properties are set by XAML.

The concision of the XAML results mostly from the brevity of the attribute values—for example, the use of the word "Large" rather than a call to the Device.GetNamedSize method. These abbreviations are not built into the XAML parser. The XAML parser is instead assisted by various converter classes defined specifically for this purpose.

When the XAML parser encounters the Label element, it can use reflection to determine whether Xamarin.Forms has a class named Label, and if so, it can instantiate that class. Now it is ready to initialize that object. The Text property is of type string, and the attribute value is simply assigned to that property.

The IsVisible and Opacity properties of Label are of type bool and double, respectively, and these are as simple as you might expect. The XAML parser uses the Boolean.Parse and Double.Parse methods to convert the attribute values. The Boolean.Parse method is case insensitive, but generally Boolean values are capitalized as “True” and “False” in XAML. The Double.Parse method is passed a CultureInfo.InvariantCulture argument, so the conversion doesn’t depend on the local culture of the programmer or user.

The HorizontalTextAlignment property of Label is of type TextAlignment, which is an enumeration. For any property that is an enumeration type, the XAML parser uses the Enum.Parse method to convert from the string to the value.

The VerticalOptions property is of type LayoutOptions, a structure. When the XAML parser references the LayoutOptions structure using reflection, it discovers that the structure has a C# attribute defined:

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

The TypeConverter attribute is supported by a class named TypeConverterAttribute. This particular TypeConverter attribute on LayoutOptions references a class named LayoutOptionsConverter, which derives from a public abstract class named TypeConverter that defines methods named CanConvertFrom and ConvertFrom. When the XAML parser encounters this TypeConverter attribute, it instantiates the LayoutOptionsConverter. The VerticalOptions attribute in the XAML is assigned the string “Center”, so the XAML parser passes that “Center” string to the ConvertFrom method of LayoutOptionsConverter, and out pops a LayoutOptions value. This is assigned to the VerticalOptions property of the Label object.

like image 69
deczaloth Avatar answered Mar 05 '23 17:03

deczaloth