Forum Xamarin.Forms
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

TypeConverter is not called when data binding in Xamarin Forms

AndjanAndjan Member ✭✭

I'm trying to bind an enum to Picker control and display localized names to the user. I use the same code that works perfectly in my WPF app, but for some reason it doesn't work in Xamarin Forms and it displays enum's named constants instead of localized names. It looks like that TypeConverter is not called. I checked that the type converter works as expected: TypeDescriptor.GetConverter(typeof(Country)).ConvertTo(Country.sr, typeof(string)) as string; returns localized name.

Here is my type converter class

public class EnumDescriptionTypeConverter : EnumConverter
{
    public EnumDescriptionTypeConverter(Type type)
        : base(type)
    {
    }

    public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(string))
        {
            if (value != null)
            {
                FieldInfo fi = value.GetType().GetField(value.ToString());
                if (fi != null)
                {
                    var attributes = (DescriptionAttribute[])fi.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    return ((attributes.Length > 0) && (!String.IsNullOrEmpty(attributes[0].Description))) ? attributes[0].Description : value.ToString();
                }
            }

            return string.Empty;
        }

        return base.ConvertTo(context, culture, value, destinationType);
    }
}

and my DescriptionAttribute class

public class LocalizedDescriptionAttribute : DescriptionAttribute
{
    ResourceManager _resourceManager;
    readonly string _resourceKey;

    public LocalizedDescriptionAttribute(string resourceKey, Type resourceType)
    {
        _resourceManager = new ResourceManager(resourceType);
        _resourceKey = resourceKey;
    }

    public override string Description
    {
        get
        {
            string description = _resourceManager.GetString(_resourceKey);
            return string.IsNullOrWhiteSpace(description) ? string.Format("[[{0}]]", _resourceKey) : description;
        }
    }
}

and my enum

[TypeConverter(typeof(EnumDescriptionTypeConverter))]
public enum Country
{
    [LocalizedDescription("sl", typeof(Resource))]
    sl,
    [LocalizedDescription("sr", typeof(Resource))]
    sr,
    [LocalizedDescription("th", typeof(Resource))]
    th
}

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai

    We consumed the IValueConverter directly in Forms. So I suggest using the below approach to achieve the effect.
    Firstly, define our own converter:

    public class MyEnumConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            ObservableCollection<Country> enums = (ObservableCollection<Country>)value;
            ObservableCollection<string> enumStrings = new ObservableCollection<string>();
            foreach(Country country in enums)
            {
                var localString = Enum.GetName(typeof(Country), country);
                enumStrings.Add(_resourceManager.GetString(localString));
            }
    
            return enumStrings;
        }
    
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
    

    Then initialize a Picker on the page:

    <ContentPage.Resources>
        <local:MyEnumConverter x:Key="MyEnumConverter"/>
    </ContentPage.Resources>
    <StackLayout>
        <Picker ItemsSource="{Binding PickerSource, Converter={StaticResource MyEnumConverter}}"/>
    </StackLayout>
    

    Here is the Source in the view model:

    PickerSource = new ObservableCollection<Country> { Country.sl, Country.sr, Country.th };
    
  • AndjanAndjan Member ✭✭

    Thanks @LandLu.
    I'm aware that I can use IValueConverter for this task. My issue is that I have about 70 enums in my app and I have to refactor them to use IValueConverter, as well as all views where those enums are used. That is way I would like to figure out why TypeConverter doesn't work since it would save me a lot of effort.

  • LandLuLandLu Member, Xamarin Team Xamurai

    I will try to do some research about the TypeConverter.
    You could use IValueConverter as an alternative. We still have to add all the values into a list as the items source even though we are consuming TypeConverter.

  • AndjanAndjan Member ✭✭

    Yes, I already have this done.
    I have an existing WPF app that uses TypeConverter for this task. Now I have to make a new mobile app that will use view models of the WPF app. Since we will make additional development on both apps in parallel I wan't to avoid any refactoring on view models and models if possible.

Sign In or Register to comment.