在Enum中填充的ListPicker中使用本地化字符串

时间:2013-09-03 14:01:41

标签: c# data-binding windows-phone-8 combobox enums

我正在填充ListPicker的{​​{1}}。例如,如果我有以下枚举:

Enum

我按以下方式填充ListPicker:

public enum Pets 
{
    Dog,
    Cat,
    Platypus 
}

一切都好,直到那里。我的ListPicker控件显示要选择的项的名称。

问题在于我想将Enum项目本地化以便在不同语言中使用它们。也就是说,我希望ListPicker以应用程序当前使用的语言显示名称。

我在资源文件中有本地化字符串,我用它来本地化应用程序的其余部分。但是,我不知道如何使它与ListPicker项一起使用。

3 个答案:

答案 0 :(得分:6)

我终于找到了一种方法,使用Description属性来实现我的目标,用于枚举值和Converter

由于无法将Resources文件中的值直接用作Description属性,因此我首先创建了自定义的LocalizedDescriptionAttribute类,该类继承自DescriptionAttribute:

public class LocalizedDescriptionAttribute : DescriptionAttribute
{
    public LocalizedDescriptionAttribute(string resourceId)
        : base(GetStringFromResource(resourceId))
    { }

    private static string GetStringFromResource(string resourceId)
    {
        return AppResources.ResourceManager.GetString(resourceId);
    }
}

这样我可以将资源的ID用作LocalizedDescription属性:

public enum Pet
{
    [LocalizedDescription("Dog")]
    Dog,
    [LocalizedDescription("Cat")]
    Cat,
    [LocalizedDescription("Platypus")]
    Platypus 
}

在这里,我创建了一个ValueConverter,它在ListPicker中用适当的语言来完成字符串的工作:

public class EnumToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value != null)
        {
            Type type = value.GetType();
            string name = Enum.GetName(type, value);
            if (name != null)
            {
                FieldInfo field = type.GetField(name);
                if (field != null)
                {
                    DescriptionAttribute attr =
                           Attribute.GetCustomAttribute(field,
                             typeof(DescriptionAttribute)) as DescriptionAttribute;
                    if (attr != null)
                    {
                        return attr.Description;
                    }
                }
            }
        }
        return null;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

完成此操作后,我为ListPicker项创建了DataTemplate,将TextBlock的Text属性值设置为Binding并使用Converter

<DataTemplate x:Key="ListPickerDataTemplate">
    <Grid>
        <TextBlock Text="{Binding Converter={StaticResource EnumToStringConverter}}"/>
    </Grid>
</DataTemplate>

我按照以前的方式填充ListPicker:

PetListPicker.ItemsSource = Enum.GetValues(typeof(Pet));

现在我的ListPicker显示了项目的本地化值,其优点是ListPicker的SelectecItem属性可以绑定到Enum类型的属性。

例如,如果我的ViewModel中有以下属性,我想要存储所选项目:

public Pet MyPet {get; set;};

我可以使用绑定:

<toolkit:ListPicker x:Name="MyListPicker" SelectedItem="{Binding MyPet, Mode=TwoWay}" ItemTemplate="{StaticResource ListPickerDataTemplate}"/>

答案 1 :(得分:1)

最简单的方法是编写一个方法来查找已翻译的字符串并将其返回到数组中。 (您也可以通过向枚举添加属性来实现,但我个人认为这比它的价值要麻烦得多。)

我的意思是这样的:

public string[] TranslatedPetsEnum()
{
    string[] result = new []
    {
        Resources.PetCat,
        Resources.PetDog,
        Resources.PetPlatypus
    };

    return result;
}

然后你就做了:

PetListPicker.ItemsSource = TranslatedPetsEnum();

如果您只想翻译一个枚举值:

public string TranslatePet(Pets pet)
{
    switch (pet)
    {
        case Pets.Dog:      return Resources.PetDog;
        case Pets.Cat:      return Resources.PetCat;
        case Pets.Platypus: return Resources.PetPlatypus;
        default:            return Resources.PetUnknown;
    }
}

您还可以使用可能更易维护的TranslatedPetsEnum()来实施TranslatePet()

public string[] TranslatedPetsEnum()
{
    Pets[] pets = (Pets[]) Enum.GetValues(typeof(Pets));
    string[] result = new string[pets.Length];

    for (int i = 0; i < pets.Length; ++i)
        result[i] = TranslatePet(pets[i]);

    return result;
}

(还有一点:正确的命名约定应该是调用枚举Pet,而不是Pets。多个枚举名称应该用于具有可以进行OR运算的值的枚举。)

答案 2 :(得分:0)

我在WPF中的首选方法是在Windows Phone中运行:

<ComboBox SelectedValuePath="Tag" SelectedValue="{Binding Side}">
     <ComboBoxItem Tag="{x:Static local:Side.Bid}" Content="Buy"/>
     <ComboBoxItem Tag="{x:Static local:Side.Ask}" Content="Sell"/>
</ComboBox>

内容中的“购买”和“销售”独立于Binding,然后以与其他所有内容相同的方式进行本地化。与接受的答案相比,这种方法确实有不同的优点和缺点,因此它可能对某些人有益。

由于ListPicker不支持SelectedValueSelectedValuePath,并且Windows Phone不支持x:Static,因此在Windows Phone中无法做到这一点 - 除非你有一个GUI库,它比工具包中的ListPicker更有用SelectedValuePath。如果您更昂贵的ListPicker支持x:Static,请向下滚动以了解如何解决<toolkit:ListPicker Name="picker" SelectionChanged="OnSelectionChanged"> <toolkit:ListPickerItem Content="Buy" Tag="{x:Static local:Side.Bid}" /> <toolkit:ListPickerItem Content="Sell" Tag="{x:Static local:Side.Ask}" /> </toolkit:ListPicker> void OnSelectionChanged(...) { if (DataContext != null && picker.SelectedItem != null) (DataContext as MyClass).Side= (Side)(((ListPickerItem)picker.SelectedItem).Tag); } void Init() { picker.SelectedItem = picker.Items.First(i => (DataContext as MyClass).Side.Equals(((ListPickerItem)i).Tag)); } 的缺失问题。

可以通过跳过Binding(或通过绑定到set / get后面的代码中的中间变量)来完成一些类似的实现:

x:Static

当然,这不起作用因为Windows Phone 8不支持public class StaticSideEnums { public static Side Bid { get { return Side.Bid; } } public static Side Ask { get { return Side.Ask; } } } <ResourceDictionary> <local:StaticSideEnums x:Key="StaticSideEnums"/> </ResourceDictionary> <toolkit:ListPicker Name="picker" SelectionChanged="OnSelectionChanged"> <toolkit:ListPickerItem Content="Buy" Tag="{Binding Bid, Source={StaticResource StaticSideEnums}}" /> <toolkit:ListPickerItem Content="Sell" Tag="{Binding Ask, Source={StaticResource StaticSideEnums}}" /> </toolkit:ListPicker> 。为了解决这个问题,我们需要这个小宝石:

{{1}}