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.
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:
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....
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.