1

I have ran into a peculiar one that is halting development on my app. I have a picker that the user can select payment types from (this app doesn't handle payment, its an expenses page). I have pictured this below.

The picker

Behind the picker is an Enum called Payment Type. I have used some code from out and about to convert the enum name to a more pleasing string format (CreditCard -> Credit Card).

References for this: enum set to string and get sting value when need https://alexdunn.org/2017/05/16/xamarin-tip-binding-a-picker-to-an-enum/

I am using MVVM and databinding to set this picker, here is the property that the picker is binding to:

PaymentType _selectedPaymentMethod;
public string SelectedPaymentMethod
{
    set
    {
        var enumValue = _enumHelper.ConvertStringToPaymentTypeEnum(value);//ConvertStringToEnum<PaymentType>(value);

        if(SetProperty(ref _selectedPaymentMethod, enumValue))
        {
            _expenseItem.PaymentType = _selectedPaymentMethod;
            _canCreateExpense = validateForm();
        }
    }
    get
    {
        return _enumHelper.ConvertPaymentTypeEnumToString(_selectedPaymentMethod);//ConvertEnumToString<PaymentType>(_selectedPaymentMethod);
    }
}

Before we look at the methods being called, lets have a look at our enum:

public enum PaymentType
    {
        [Description("None")] 
        None,

        [Description("Credit Card")] 
        CreditCard,

        [Description("Cash")] 
        Cash
    }

So I have an enum helper class which I am using to Convert the enum to a string and back. I found if I put the enum directly into the picker, I was left with poorly formatted text, and if I formatted the text the set event was never fired. So I have to convert my enum to a List<string> to display it and convert back to process it. Also the enum has a default value of none which I hide from the view, the enum default to 0 so when I call validate I how the property hasn't been set.

Lets now look at the methods I am calling:

public PaymentType ConvertStringToPaymentTypeEnum(string text)
{
    foreach (var value in Enum.GetValues(typeof(PaymentType)))
    {
        PaymentType enumValue = (PaymentType)value;

        if (text == enumValue.GetDescription())
        {
            return enumValue;
        }
    }

    return 0;
}

public string ConvertPaymentTypeEnumToString(PaymentType paymentType)
{
    foreach (var value in Enum.GetValues(typeof(PaymentType)))
    {
        PaymentType enumValue = (PaymentType)value;

        if (paymentType == enumValue)
        {
            return paymentType.GetDescription();
        }
    }

    return "";
}

This all works well and the app functions properly, take a look at it in action:

The app running on non generic code

Now, this enum method was hardcoded to 1 enum type, these 2 methods are un-reusable... which I don't want as I might want to use it elsewhere. So once I implemented it here I decided to convert these methods to use generic types, so I could use them with other enums. Lets take a look at what I did.

public T ConvertStringToEnum<T>(string text)
{
    foreach (var value in Enum.GetValues(typeof(T)))
    {
        T enumValue = (T)value;

        var enumVal = enumValue as Enum;

        if (text == enumVal.GetDescription())
        {
            return enumValue;
        }
    }

    return default(T);
}

public string ConvertEnumToString<T>(Enum @enum)
{
    foreach (var value in Enum.GetValues(typeof(T)))
    {
        Enum enumValue = (T)value as Enum;

        if (@enum == enumValue)
        {
            return @enum.GetDescription();
        }
    }

    return "";
}

Now if I call these new methods (notice them commented out earlier), I run into the stupidest most non sensical bug ever. Both methods work and return what I want however the setter gets called again and the methods return default (specifically the first method, ConvertStringToEnum)

Look at how the app now runs....

The app running on generic code

So when I change my method type to generic, the setter of ProcessedState gets called twice.... what?

I have no idea whats going on here and googling didn't seem to help. What in the name of Xamarin is happening?

note I am using Prism DryIos for this app, however i strongly doubt it is causing the issue here.

Bodungus
  • 175
  • 14
  • Why do you first cast to `T` and then to `Enum`? Are you sure there are no exceptions? `enumVal` might be `null` for example, not to mention string values not corresponding to any defined enum value. – Haukinger Mar 22 '18 at 19:02
  • @Haukinger The code wouldn't run properly if I wrote `Enum enumValue = (T)value` and passed `enumValue` to the rest of my function. I guarantee the function is working, I should have shown a gif of debugging. The set method gets called, the correct enum value is set.... and then another set call gets made and the enum is reset to `PaymentType.None` – Bodungus Mar 22 '18 at 19:49
  • @Haukinger I think its an issue with binding, the control is clearly not accept the value in my view model – Bodungus Mar 22 '18 at 20:24
  • The issue was with the second method, enum to string. The enum compare was never executing even if it was correct. I've done this to fix `if (@enum.ToString() == enumValue.ToString())`, doesn't seem great but it works for now. Since my value was never getting set then a new event was raised to reset the value. – Bodungus Mar 22 '18 at 23:00

0 Answers0