0
votes

I needed a solution for parsing a string to an int in order to use with the InputSelect of Blazor.

I found this solution which works pretty well.

Now with my models

public class Book
    {
        [Required]
        public int Id { get; set; }
        [Required]
        public int CategoryId { get; set; }
        public Category Category { get; set; }
        ...
        [Required]
        public EnumLanguages Language { get; set; }
}

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
}

I can use it in my Razor page like this:

<InputSelectNumber id="category" @bind-Value="@Book.CategoryId">
       @foreach (var category in Categories)
       {
            <option value="@category.Id">@category.Name</option>
       }
</InputSelectCustom>

With that in place I can use my CategoryId (which is int) directly on my InputSelectNumber tag. So far so good.

Now I need to do the same for enumerations like EnumLanguages

public enum EnumLanguages
{
    English,
    French
}

I updated the InputSelectNumber class like this:

public class InputSelectNumber<T> : InputSelect<T>
{
    protected override bool TryParseValueFromString(string value, out T result, out string validationErrorMessage) 
    {
        if (typeof(T) == typeof(int))
        {
            if (int.TryParse(value, out var resultInt))
            {
                result = (T)(object)resultInt;
                validationErrorMessage = null;
                return true;
            }
            else
            {
                result = default;
                validationErrorMessage = "The chosen value is not valid.";
                return false;
            }
        }
        else 
        if (typeof(T) == typeof(EnumLanguages))
        {
            if (Enum.TryParse<EnumLanguages>(value, out var resultEnum))
            {
                result = (T)(object)resultEnum;
                validationErrorMessage = null;
                return true;
            }
            else
            {
                result = default;
                validationErrorMessage = "The chosen value is not valid.";
                return false;
            }
        }
        else
        {
            return base.TryParseValueFromString(value, out result, out validationErrorMessage);
        }
    }
}

And use it:

<InputSelectNumber @bind-Value="Book.Language">
      <option value="English">English</option>
      <option value="French">French</option>
</InputSelectCustom>

As you can see, I added a second block of code where I hard coded the EnumLanguages in my code. But I would prefer using a generic code for Enums but I don't know if this is feasible. Please not that I cannot change the signature of the method because it is an override.

1

1 Answers

1
votes

You can use such way:

 protected override bool TryParseValueFromString(string value, out T result, out string validationErrorMessage)
    {
        if (typeof(T) == typeof(int))
        {
            if (int.TryParse(value, out var resultInt))
            {
                result = (T)(object)resultInt;
                validationErrorMessage = null;
                return true;
            }
            else
            {
                result = default;
                validationErrorMessage = "The chosen value is not valid.";
                return false;
            }
        }
        else  if (typeof(T).IsEnum)
        {
            if (EnumTryParse<T>(value, out var resultEnum))
            {
                result = (T)(object)resultEnum;
                validationErrorMessage = null;
                return true;
            }
            else
            {
                result = default;
                validationErrorMessage = "The chosen value is not valid.";
                return false;
            }
        }
        else
        {
            return base.TryParseValueFromString(value, out result, out validationErrorMessage);
        }
    }

And this extent method:

public static bool EnumTryParse<T>(string input, out T theEnum)
    {
        foreach (string en in Enum.GetNames(typeof(T)))
        {
            if (en.Equals(input, StringComparison.CurrentCultureIgnoreCase))
            {
                theEnum = (T)Enum.Parse(typeof(T), input, true);
                return true;
            }
        }

        theEnum = default(T);
        return false;
    }

Final use

    <InputSelectNumber @bind-Value="@language" T="@EnumLanguages">
    <option value="English">English</option>
    <option value="French">French</option>
</InputSelectNumber>