3
votes

In Xamarin Forms I'm trying to create a xaml converter with properties. This is to be used, for example, to show values from a list in different ways, based on a code behind property.

I based my code on this: https://stackoverflow.com/a/29869734.

Converter:

namespace App2.Converters
{
    class MyConverter : IValueConverter
    {

        public int ConvParam { get; set; }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return $"value: {value} - ConvParam: {ConvParam}";
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

XAML:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:conv="clr-namespace:App2.Converters"
         x:Class="App2.MainPage"
         x:Name="MainPageXaml">

<ContentPage.Resources>
    <conv:MyConverter x:Key="cnv" ConvParam="{Binding Source={Reference MainPageXaml}, Path=PropParam}" />
    <!--<conv:MyConverter x:Key="cnv" ConvParam="333" />-->
</ContentPage.Resources>

<StackLayout Orientation="Vertical">
    <!-- Place new controls here -->
    <Label Text="{Binding Source={Reference MainPageXaml}, Path=PropVal}" />
    <Label Text="{Binding Source={Reference MainPageXaml}, Path=PropParam}" />
    <Label Text="{Binding Source={Reference MainPageXaml}, Path=PropVal, Converter={StaticResource cnv}}" />
</StackLayout>

Code behind:

public partial class MainPage : ContentPage
{

    public int PropVal { get; set; } = 111;
    public int PropParam { get; set; } = 222;

    public MainPage()
    {
        InitializeComponent();
    }
}

The goal is to bind ConvParam of my converter to PropParam in code behind.

But if I use:

<conv:MyConverter x:Key="cnv" ConvParam="{Binding Source={Reference MainPageXaml}, Path=PropParam}" />

the error Position 10:39. No property, bindable property, or event found for 'ConvParam', or mismatching type between value and property is shown and the app doesn't compile.

The property ConvParam itself is recognized inside xaml: if I replace the above line with

<conv:MyConverter x:Key="cnv" ConvParam="333" />

everything works.

The binding expression I used ({Binding Source={Reference MainPageXaml}, Path=PropParam}) actually works, if used as source for the text property of a label:

<Label Text="{Binding Source={Reference MainPageXaml}, Path=PropParam}" />

But if I use it in Resources, It doesn't work.

1
You can not set a binding to a property that is not a BindableProperty! You have to define ConvParam as a BindableProperty. See xamarinhelp.com/bindable-properties-xamarin-forms - Deczaloth
Also, you should better try using the built-in ConverterParameter property instead defining your own. See docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/… - Deczaloth
Thank you Julipan, I modified my converter and defined ConvParam as BindableProperty and it worked. I don't use ConverterParameter because... it's not a BindableProperty! I will modify my question to show the working code, but I'd like to give you credits for pointing me in the right direction. - Disti
You can post your answer and accept it, which will help more people . - Lucas Zhang

1 Answers

6
votes

Thanks to Julipan I could make it work!

As he pointed out, ConvParam must be a BindableProperty, so I modified my converter to inherit from BindableObject and defined ConvParam as BindableProperty.

Converter:

namespace App2.Converters
{
    class MyConverter : BindableObject, IValueConverter
    {
        public static readonly BindableProperty ConvParamProperty = BindableProperty.Create(nameof(ConvParam), typeof(int), typeof(MyConverter));

        public int ConvParam
        {
            get { return (int)GetValue(ConvParamProperty); }
            set { SetValue(ConvParamProperty, value); }
        }

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return $"value: {value} - ConvParam: {ConvParam}";
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}