Подтвердить что ты не робот

Enum в WPF ComboxBox с локализованными именами

У меня есть ComboBox с перечислением Enum.

enum StatusEnum {
    Open = 1, Closed = 2, InProgress = 3
}

<ComboBox ItemsSource="{Binding StatusList}"
          SelectedItem="{Binding SelectedStatus}" />

Я хочу отображать локализованные имена для значений перечисления на английском языке

Open
Closed
In Progress

но также и на немецком (и в других языках в будущем)

Offen
Geschlossen
In Arbeit

В моей модели ViewModel с помощью

public IEnumerable<StatusEnum> StatusList 
{
    get 
    {
        return Enum.GetValues(typeof(StatusEnum)).Cast<StatusEnum>();
    }
}

получает только имена перечисления в коде, а не переведенные.

У меня есть общая локализация на месте и вы можете получить к ним доступ, используя i.e.

Resources.Strings.InProgress

который возвращает мне перевод для текущего языка.

Как я могу автоматически привязать локализацию?

4b9b3361

Ответ 1

Это пример простого Enum для переведенного строкового преобразователя.

public sealed class EnumToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
        { return null; }

        return Resources.ResourceManager.GetString(value.ToString());
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        string str = (string)value;

        foreach (object enumValue in Enum.GetValues(targetType))
        {
            if (str == Resources.ResourceManager.GetString(enumValue.ToString()))
            { return enumValue; }
        }

        throw new ArgumentException(null, "value");
    }
}

Также вам понадобится MarkupExtension, который предоставит значения:

public sealed class EnumerateExtension : MarkupExtension
{
    public Type Type { get; set; }

    public EnumerateExtension(Type type)
    {
        this.Type = type;
    }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        string[] names = Enum.GetNames(Type);
        string[] values = new string[names.Length];

        for (int i = 0; i < names.Length; i++)
        { values[i] = Resources.ResourceManager.GetString(names[i]); }

        return values;
    }
}

Использование:

<ComboBox ItemsSource="{local:Enumerate {x:Type local:StatusEnum}}"
          SelectedItem="{Binding SelectedStatus, Converter={StaticResource EnumToStringConverter}}" />

РЕДАКТИРОВАТЬ: Вы можете сделать более сложный преобразователь значений и расширение разметки. EnumToStringConverter может использовать DescriptionAttribute, чтобы получить переведенные строки. И EnumerateExtension может использовать TypeConverter.GetStandardValues() и конвертер. Это позволяет получать стандартные значения указанного типа (не только Enum s) и преобразовывать их в строки или что-то другое в зависимости от преобразователя.

Пример:

<ComboBox ItemsSource="{local:Enumerate {x:Type sg:CultureInfo}, Converter={StaticResource CultureToNameConverter}}"
          SelectedItem="{Binding SelectedCulture, Converter={StaticResource CultureToNameConverter}}" />

EDIT: Более сложное решение, описанное выше, опубликовано на GitHub.

Ответ 2

Вы не можете, из коробки.

Но вы можете создать свойство ObservableList<KeyValuePair<StatusEnum, string>> и заполнить его своим перечислением/локализованным текстом, а затем привязать его к ComboBox.

Что касается самой строки:

var localizedText = (string)Application.Current.FindResource("YourEnumStringName");

Получение строкового представления Enum с помощью методов Enum.GetName/Enum.GetNames.

Ответ 3

Вы можете использовать атрибут для перечисления и написать метод расширения для перечисления. См. Приведенный ниже код.

<ComboBox Width="200" Height="25" ItemsSource="{Binding ComboSource}"
          DisplayMemberPath="Value"
          SelectedValuePath="Key"/>


public class MainViewModel
{
    public List<KeyValuePair<Status, string>> ComboSource { get; set; }

    public MainViewModel()
    {
        ComboSource = new List<KeyValuePair<Status, string>>();
        Status st=Status.Open;
        ComboSource = re.GetValuesForComboBox<Status>();
    }
}

public enum Status
{
    [Description("Open")]
    Open,
    [Description("Closed")]
    Closed,
    [Description("InProgress")]
    InProgress
}

 public static class ExtensionMethods
    {
        public static List<KeyValuePair<T, string>> GetValuesForComboBox<T>(this Enum theEnum)
        {
            List<KeyValuePair<T, string>> _comboBoxItemSource = null;
            if (_comboBoxItemSource == null)
            {
                _comboBoxItemSource = new List<KeyValuePair<T, string>>();
                foreach (T level in Enum.GetValues(typeof(T)))
                {
                    string Description = string.Empty;
                    FieldInfo fieldInfo = level.GetType().GetField(level.ToString());
                    DescriptionAttribute[] attributes = (DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
                    if (attributes != null && attributes.Length > 0)
                    {
                        Description = GetDataFromResourceFile(attributes.FirstOrDefault().Description);
                    }
                    KeyValuePair<T, string> TypeKeyValue = new KeyValuePair<T, string>(level, Description);
                    _comboBoxItemSource.Add(TypeKeyValue);
                }
            }
            return _comboBoxItemSource;
        }

        public static string GetDataFromResourceFile(string key)
        {
            //Do you logic to get from resource file based on key for a language.
        }
    }

Я уже опубликовал аналогичную вещь в SO Возможно ли связать привязку к Enum и показать удобные для пользователя значения?