Utilizzo di stringhe localizzate in un ListPicker popolato da Enum

Sto popolando un ListPicker da un Enum . Ad esempio, se ho il seguente Enum:

 public enum Pets { Dog, Cat, Platypus } 

Compilo il ListPicker nel modo seguente:

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

Tutto OK fino a lì. Il mio controllo ListPicker mostra i nomi degli elementi da scegliere.

Il problema è che voglio localizzare quegli oggetti Enum per usarli in diverse lingue. Cioè, mi piacerebbe che ListPicker mostri i nomi nella lingua attualmente utilizzata dall’app.

Ho localizzato le stringhe nei file di risorse, che uso per localizzare il resto dell’app. Tuttavia, non so come farlo funzionare con gli oggetti ListPicker.

Ho finalmente trovato un approccio per raggiungere il mio objective utilizzando l’attributo Description per i valori enum e un Converter .

Dal momento che non è ansible utilizzare direttamente i valori dal file Risorse come attributi Descrizione, prima di tutto ho creato la mia class LocalizedDescriptionAttribute personalizzata, che eredita da DescriptionAttribute:

 public class LocalizedDescriptionAttribute : DescriptionAttribute { public LocalizedDescriptionAttribute(string resourceId) : base(GetStringFromResource(resourceId)) { } private static string GetStringFromResource(string resourceId) { return AppResources.ResourceManager.GetString(resourceId); } } 

In questo modo posso utilizzare l’ID della risorsa come attributo LocalizedDescription:

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

Una volta qui, ho creato un ValueConverter che esegue il lavoro di shwoing della stringa nella lingua appropriata nel mio 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(); } } 

Fatto questo, ho creato un DataTemplate per gli oggetti ListPicker, impostando il valore della proprietà Text di un TextBlock con un Binding e utilizzando il Converter :

      

E popolo il ListPicker nello stesso modo in cui l’ho fatto prima:

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

Ora il mio ListPicker mostra i valori localizzati degli elementi, con il vantaggio che la proprietà SelectecItem di ListPicker può essere associata a una proprietà del tipo di Enum.

Ad esempio, se ho la seguente proprietà nel mio ViewModel, dove voglio memorizzare l’elemento selezionato:

 public Pet MyPet {get; set;}; 

Posso solo usare una rilegatura:

  

Il modo più semplice per farlo è scrivere un metodo che cerchi le stringhe tradotte e le restituisca in un array. (Puoi farlo anche aggiungendo attributi all’enumerazione, ma personalmente penso che sia molto più difficile di quanto valga.)

Quello che voglio dire è qualcosa del genere:

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

Quindi devi solo fare:

 PetListPicker.ItemsSource = TranslatedPetsEnum(); 

Se vuoi solo tradurre un valore enum:

 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; } } 

È inoltre ansible implementare TranslatedPetsEnum() utilizzando TranslatePet() che potrebbe essere più gestibile:

 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; } 

(Anche un piccolo punto: la convenzione di denominazione corretta dovrebbe essere quella di chiamare l'enum Pet , non gli Pets . Si suppone che i nomi enum plurali siano usati per enumerazioni che hanno valori che possono essere ordinati insieme).

Il mio approccio preferito in WPF, che non funziona in Windows Phone è questo:

     

“Acquista” e “Vendi” nel contenuto sono indipendenti dal Binding e vengono quindi localizzati nello stesso modo in cui è tutto il resto. Questo approccio ha diversi vantaggi e svantaggi rispetto alla risposta accettata, quindi potrebbe essere di beneficio ad alcune persone.

Perché ListPicker non supporta SelectedValue e SelectedValuePath , e Windows Phone non supporta x:Static , questo non può essere fatto banalmente in Windows Phone – a meno che tu non abbia una libreria della GUI con un ListPicker più utile di quello nel toolkit. Se il tuo ListPicker più costoso supporta SelectedValuePath , scorri verso il basso per vedere come puoi aggirare la mancanza di x:Static .

Un’implementazione in qualche modo simile può essere fatta saltando il Binding (o vincolando ad una variabile intermedia nel codice dietro per set / get):

     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)); } 

Ovviamente non funzionerà perché Windows Phone 8 non supporta x:Static . Per ovviare a questo abbiamo bisogno di questo piccolo gioiello:

 public class StaticSideEnums { public static Side Bid { get { return Side.Bid; } } public static Side Ask { get { return Side.Ask; } } }