Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

mvvmcross: How to use enum values as ItemsSource

Tags:

mvvmcross

I have the following in my model:

public class Equipment
{
    public enum Type
    {
        Detector,
        VegetationClearance,
        Removal,
        Engaging
    }
}

And in the view model:

    private Equipment.Type _equipmentType;
    public Equipment.Type EquipmentType
    {
        get { return _equipmentType; }
        set
        {
            _equipmentType = value;
            RaisePropertyChanged(() => EquipmentType);
        }
    }

And I want to use the values as an ItemsSource so that the user can select from the enumeration:

    <Mvx.MvxSpinner
        android:id="@+id/type"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        local:MvxBind="ItemsSource Equipment.Type; SelectedItem TypeSelection" />

This doesn't work at all. Is there a way to bind an enumeration as an ItemsSource?

like image 957
Jeremy Avatar asked Mar 20 '23 14:03

Jeremy


1 Answers

EDIT: Better solution

As Anders commented, Enum.GetValues() is probably a better idea. One of the issues in binding to enums is that the identifier can't include spaces, so by default, binding will not give you a nice readable string.

However, you can decorate your enum with a Display attribute. Reference System.ComponentModel.DataAnnotations.

public class Equipment
{
    public enum Type
    {
        Detector,
        [Display(Name="Vegetation Clearance")]
        VegetationClearance,
        Removal,
        Engaging
    }
}

Now add the following properties to your ViewModel:

public IEnumerable<Equipment.Type> EquipmentTypes
{
    get { return Enum.GetValues(typeof(Equipment.Type)).Cast<Equipment.Type>(); }
}

private Equipment.Type _selectedType;
public Equipment.Type SelectedType
{
    get { return _selectedType; }
    set { _selectedType = value; RaisePropertyChanged(() => SelectedType); }
}

What we are going to do is create a Value Converter that converts an enum into a string for display that will return the Display Name attribute if present.

public class EnumDisplayNameValueConverter : MvxValueConverter
{
    public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return GetEnumDisplayName((Enum)value);
    }

    public static string GetEnumDisplayName(Enum value)
    {
        var t = value.GetType();
        var ti = t.GetTypeInfo();
        var fi = ti.DeclaredFields.FirstOrDefault(x => x.Name == value.ToString());

        var attributes = (DisplayAttribute[])fi.GetCustomAttributes(typeof(DisplayAttribute), false);

        if (attributes != null && attributes.Length > 0)
        {
            return attributes[0].Name;
        }
        return value.ToString();
    }
}

In order to use the value converter, you'll need to specify the item template and drop down template in your spinner:

<Mvx.MvxSpinner
    android:id="@+id/type"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    local:MvxItemTemplate="@layout/spinneritem"
    local:MvxDropDownItemTemplate="@layout/spinnerdropdownitem"
    local:MvxBind="ItemsSource EquipmentTypes; SelectedItem SelectedType" />

And create the spinneritem/spinnerdropdownitem layouts:

<?xml version="1.0" encoding="utf-8" ?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:textAppearance="?android:attr/textAppearanceMedium"
    local:MvxBind="Text EnumDisplayName(.)" />

Notice that we bind to EnumDisplayName(.). That is the value converter and the . means the current value which is the enum.

I've added a sample on GitHub. https://github.com/kiliman/MvxSpinnerEnumSample

like image 144
Kiliman Avatar answered Apr 02 '23 12:04

Kiliman