Troubles with binding drawable icons in dropdown in MVVMCross Xamarin.Android

559 Views Asked by At

I need to add pictures to dropdown items.
In the dropdown I need to see the icon first and the text below. But for some reason, I can't see images, though I see the empty place instead.

My project is Xamarin.Android with MVVMCross. I'm missing something, maybe I need some plugins?

I have MypageView.axml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <include
        layout="@layout/toolbar" />
    <TextView
        android:id="@+id/city"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:layout_marginBottom="8dp"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:textSize="12sp"
        android:layout_below="@id/toolbar"
        local:MvxBind="Text Strings[CityTextView]" />
    <MvxSpinner
        android:id="@+id/select_city"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:layout_marginBottom="24dp"
        android:layout_marginLeft="16dp"
        android:layout_marginRight="16dp"
        android:spinnerMode="dropdown"
        android:layout_below="@id/city"
        local:MvxItemTemplate="@layout/item_city"
        local:MvxDropDownItemTemplate="@layout/item_city"
        local:MvxBind="ItemsSource Cities; SelectedItem SelectedCity" />

And item_city.axml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:local="http://schemas.android.com/apk/res-auto"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:padding="10dp">
    <ImageView
        android:id="@+id/cityImage"
        android:layout_width="35dp"
        android:layout_height="20dp"
        android:layout_marginLeft="16dp"
        android:scaleType="fitXY"
        local:MvxBind="DrawableName Name, Converter=IconsConverter" /> />
    <TextView
        android:id="@+id/cityName"
        android:layout_height="wrap_content"
        android:layout_width="match_parent"
        android:layout_marginLeft="8dp"
        android:layout_toRightOf="@id/cityImage"
        android:textSize="16sp"
        local:MvxBind="Text Name" />
</RelativeLayout>

In the Core, I have City.cs:

namespace My.cities.Core.Models
{
    public class City
    {
        public City(string Id, string Name, string Flag)
        {
            this.Id = Id;
            this.Name = Name;
            this.Flag = Flag;
        }
        public string Id { get; set; }
        public string Name { get; set; }
        public string Flag { get; set; }
    }
}

And MypageViewModel.cs:

using MvvmCross.Core.ViewModels;
using System.Collections.Generic;
using My.cities.Core.Models;

namespace My.cities.Core.ViewModels
{

    public class MypageViewModel : BaseViewModel
    {

    private City _selectedCity;

    private List<City> _cities = new List<City>()
    {
        new City("1", "London", "England")
        new City("2", "Paris", "France")
    };

    public List<City> Cities
    {
        get { return _cities; }
    }

    public City SelectedCity
    {
        get
        {
            return _selectedCity;
        }
        set
        {
            _selectedCity = value;
            RaisePropertyChanged(() => SelectedCity);
        }
    }
}
}

So I add the converter to MypageView.cs:

using Android.App;
using MvvmCross.Platform.Converters;
using System;
using System.Globalization;

namespace My.cities.Droid.Views
{   [Activity]
    class MypageView : BaseView
    {
        protected override int LayoutResource => Resource.Layout.MypageView;

        protected override void OnCreate(Bundle bundle)
        {
        base.OnCreate(bundle);
        }

        public static class CrossDeviceInfoHelper
        {
            public static string GetLocalImageUrlByPlatform(string name)
            {

                return CrossDeviceInfo.Current.Platform == Platform.Android ? $"@drawable/{name}" : name;
            }
        }

        public class IconsConverter : MvxValueConverter<string, string>
        {
            protected override string Convert(string value, Type targetType, object parameter, CultureInfo culture)
            {
                if (value == "London")
        return CrossDeviceInfoHelper.GetLocalImageUrlByPlatform("england");
                if (value == "Paris")
        return CrossDeviceInfoHelper.GetLocalImageUrlByPlatform("france");
         }
    }

Images England.png and France.png live here: My.sities.Droid\Resources\drawable-hdpi, My.sities.Droid\Resources\drawable-mdpi, and etc.

The build is successful, but I can't see my images, only empty rectangles. Why?

UPD.

I installed Xam.Plugin.DeviceInfo and changed my code. But I still can't see icons.

In debug it says:

[0:] MvxBind:Warning: 36,05 Value '' could not be parsed as a valid string identifier
[0:] MvxBind:Warning: 36,06 Value '' could not be parsed as a valid string identifier
[0:] MvxBind:Warning: 36,06 Value 'London' was not a known drawable name
[0:] MvxBind:Warning: 36,08 Value 'Paris' was not a known drawable name

UPD2.
Also, I tried to do it this way:

public class IconsConverter : MvxValueConverter<string, int>
        {
            protected override int Convert(string value, Type targetType, 
object parameter, CultureInfo culture)
            {
                switch (value)
                {
                    case "London":
                        return Resource.Mipmap.England;
                    case "Paris":
                        return Resource.Mipmap.France;
                }
            }
        }

But the error is the same:

[0:] MvxBind:Warning: 9,54 Value '' could not be parsed as a valid string identifier [0:] MvxBind:Warning: 9,63 Value '' could not be parsed as a valid string identifier [0:] MvxBind:Warning: 9,64 Value 'London' was not a known drawable name [0:] MvxBind:Warning: 9,65 Value 'Paris' was not a known drawable name

2

There are 2 best solutions below

3
fmaccaroni On

I think you are lacking the android:scaleType in your ImageView. Try using android:scaleType="fitXY".

If it is not that, try using the DrawableName binding instead of DrawableId and it's better because you can use a converter in your PCL making it cross-platform with Xam.Plugin.DeviceInfo and a helper method like this one:

public static class CrossDeviceInfoHelper
{
    public static string GetLocalImageUrlByPlatform(string name)
    {
        // Assuming we are working with Android and iOS
        return CrossDeviceInfo.Current.Platform == Platform.Android ? $"@drawable/{name}" : name;
    }
}

So you'll endup with a Converter like this one:

public class StringToIntValueConverter : MvxValueConverter<string, string>
{
    protected override string Convert(string value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == "London")
            return CrossDeviceInfoHelper.GetLocalImageUrlByPlatform("england");
        if (value == "Paris")
            return CrossDeviceInfoHelper.GetLocalImageUrlByPlatform("france");
    }
}

Also if I were you I'll add an enum or something that tells you the country in your City class so that you don't have to compare strings in the converter and you could also have a Dictionary in your converter that has which city goes with which country image so that you can just call CrossDeviceInfoHelper.GetLocalImageUrlByPlatform(myDictionary[value]); and therefore not using ifs

2
Cheesebaron On

The binding expression DrawableName Name Converter=IconsConverter is wrong. You are missing a comma:

DrawableName Name, Converter=IconsConverter

Alternatively you can write it like:

DrawableName Icons(Name)