2009-05-27 24 views
13

Sorun şu ki, bu numaraya sahip olduğum, AMA kutunun enum değerlerini göstermesini istemiyorum. Seçilmiş veya ActiveAndSelected, ben enum her değeri için DescriptionProperty görüntülemek istediğiniz ComboBox yerine Aktif görüntüleyen YaniWPF ciltleme ComboBox enum'a (bir twist ile)

public enum Mode 
    { 
     [Description("Display active only")] 
     Active, 
     [Description("Display selected only")] 
     Selected, 
     [Description("Display active and selected")] 
     ActiveAndSelected 
    } 

: Bu enum olduğunu.

public static string GetDescription(this Enum enumObj) 
     { 
      FieldInfo fieldInfo = 
       enumObj.GetType().GetField(enumObj.ToString()); 

      object[] attribArray = fieldInfo.GetCustomAttributes(false); 

      if (attribArray.Length == 0) 
      { 
       return enumObj.ToString(); 
      } 
      else 
      { 
       DescriptionAttribute attrib = 
        attribArray[0] as DescriptionAttribute; 
       return attrib.Description; 
      } 
     } 

Yani ComboBox enum bağlamak VE o GetDescription uzatma yöntemi ile içerik var gösterebilen bir yolu var: Ben enum için GetDescription (denilen bir uzantısı yöntemi) var mı?

Teşekkürler!

cevap

6

Düşünme şeklinizi beğeniyorum. Ancak GetCustomAttributes yansımayı kullanır. Bu senin performansına ne yapacak? Bu yazı dışarı

Kontrol: WPF - ComboBox denetimi gösteriliyor çeteleler http://www.infosysblogs.com/microsoft/2008/09/wpf_displaying_enums_in_combob.html

+16

Dostum, yansıma özellikle bir GUI görüntülemek için gereken zaman ile karşılaştırıldığında, _that_ yavaş değil. Bir problem olmasını beklemezdim. –

+0

Eh, benim için sözümü tutmayın. Yukarıda atıfta bulunulan gönderi, bir endişe olduğunu söylüyor. –

+3

Ancak herhangi bir profil sonucu alıntılamaz. Yazar bu konuda endişeliydi, ama bu aslında bir sorun olduğu anlamına gelmez. –

3

yansıma kullanmanın Sorular ve bir kenara niteliklerini, orada bu yapabileceğini birkaç yolu vardır, ama en iyi yolu sadece olduğunu düşünüyorum numaralandırma değeri sarar küçük bir görünüm modeli sınıfı oluşturmak:

public class ModeViewModel : ViewModel 
{ 
    private readonly Mode _mode; 

    public ModeViewModel(Mode mode) 
    { 
     ... 
    } 

    public Mode Mode 
    { 
     get { ... } 
    } 

    public string Description 
    { 
     get { return _mode.GetDescription(); } 
    } 
} 

Alternatif olarak, ObjectDataProvider kullanarak içine görünebilir.

<ComboBox ItemsSource="{local:EnumValues local:Mode}"/> 

EDIT:

[MarkupExtensionReturnType(typeof(IEnumerable))] 
public class EnumValuesExtension : MarkupExtension 
{ 
    public EnumValuesExtension() 
    { 
    } 

    public EnumValuesExtension(Type enumType) 
    { 
     this.EnumType = enumType; 
    } 

    [ConstructorArgument("enumType")] 
    public Type EnumType { get; set; } 

    public override object ProvideValue(IServiceProvider serviceProvider) 
    { 
     if (this.EnumType == null) 
      throw new ArgumentException("The enum type is not set"); 
     return Enum.GetValues(this.EnumType).Select(o => GetDescription(o)); 
    } 
} 

Ardından söz konusu gibi kullanabilirsiniz:

3

Ben sadece biraz değişiklikle, zaten here yayınlanmıştır vardı bir biçimlendirme uzantısını kullanan önermek yöntemi ben SelectedItem'in Type modundan olmasını istediğimiz için istenen bir dize listesi önerilmeyecektir. .Select (...) parçasını kaldırmak ve ItemTemplate'de özel bir dönüştürücü ile bir ciltleme kullanmak daha iyi olacaktır.

+0

o Açılan kutunun SelectedItem yerine Mode.Active ait "Yalnızca Görüntülü etkin" yapmaz mı? Benim için istenmeyen bir yan etki gibi görünüyor. –

+0

Yani o enum ile nesne seçili ne bu yaklaşımla ben Seçilen öğeyi ayarlamak mümkün olmayacaktır demektir? – Carlo

+0

@Joe: evet, haklısın ... bu gerçekten bir sorun. Ben cevabım –

19

Bir DataTemplate ve bir ValueConverter öneririm. Bu, görüntülenme şeklini özelleştirmenize izin verir, ancak yine de combobox'ın SelectedItem özelliğini okuyabiliyor ve gerçek enum değerini alabiliyordunuz.

ValueConverters çok sayıda kod yazım kodu gerektirir, ancak burada çok karmaşık bir şey yok. Önce ValueConverter sınıf oluşturmak: Yalnızca dizeleri (ekran için) için enum değerlerini dönüştürme konum yana

public class ModeConverter : IValueConverter 
{ 
    public object Convert(object value, Type targetType, object parameter, 
     CultureInfo culture) 
    { 
     return ((Mode) value).GetDescription(); 
    } 
    public object ConvertBack(object value, Type targetType, object parameter, 
     CultureInfo culture) 
    { 
     throw new NotSupportedException(); 
    } 
} 

, sen ConvertBack gerekmez - sadece iki yönlü bağlama senaryoları için.

Sonra böyle bir şey ile, sizin kaynakların içine ValueConverter örneğini koyun:

:

<Window ... xmlns:WpfApplication1="clr-namespace:WpfApplication1"> 
    <Window.Resources> 
     <WpfApplication1:ModeConverter x:Key="modeConverter"/> 
    </Window.Resources> 
    .... 
</Window> 

Sonra ComboBox biçimlendiren bir DisplayTemplate vermeye hazır olduğumuzu ModeConverter kullanarak ürün

<ComboBox Name="comboBox" ...> 
    <ComboBox.ItemTemplate> 
     <DataTemplate> 
      <TextBlock Text="{Binding Converter={StaticResource modeConverter}}"/> 
     </DataTemplate> 
    </ComboBox.ItemTemplate> 
</ComboBox> 

bunu test etmek için, bana gerçek SelectedItem değerini ortaya koyacaktır de bir Label, içinde attı ve gerçekten bu SelectedItem isteyeyim ne bunun yerine görüntüleme metin enum olduğunu göstermek vermedi:

Ben MVVM ile yapıyorum nasıl
<Label Content="{Binding ElementName=comboBox, Path=SelectedItem}"/> 
+0

Dude güncellenir, cevabın nihayet internet kazı birkaç saat sonra benim sorun çözüldü. Teşekkürler! – mcy

6

budur. Ben mümkün dizesi olarak seçimleri yanı sıra/modelin değerini almak için bir özellik sağlayan bir özellik maruz benim ViewModel üzerinde

public enum VelocityUnitOfMeasure 
    { 
     [Description("Miles per Hour")] 
     MilesPerHour, 
     [Description("Kilometers per Hour")] 
     KilometersPerHour 
    } 

: my modeline benim enum tanımlanan olurdu. Yapabileceğim görüntüsü,

public class EnumDescriptionConverter : IValueConverter 
{ 
    //From Binding Source 
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (!(value is Enum)) throw new ArgumentException("Value is not an Enum"); 
     return (value as Enum).Description(); 
    } 

    //From Binding Target 
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) 
    { 
     if (!(value is string)) throw new ArgumentException("Value is not a string"); 
     foreach(var item in Enum.GetValues(targetType)) 
     { 
      var asString = (item as Enum).Description(); 
      if (asString == (string) value) 
      { 
       return item; 
      } 
     } 
     throw new ArgumentException("Unable to match string to Enum description"); 
    } 
} 

Ve nihayet:

//UI Helper 
    public IEnumerable<string> VelocityUnitOfMeasureSelections 
    { 
     get 
     { 
      var units = new [] 
          { 
           VelocityUnitOfMeasure.MilesPerHour.Description(), 
           VelocityUnitOfMeasure.KilometersPerHour.Description() 
          }; 
      return units; 
     } 
    } 

    //VM property 
    public VelocityUnitOfMeasure UnitOfMeasure 
    { 
     get { return model.UnitOfMeasure; } 
     set { model.UnitOfMeasure = value; } 
    } 

Dahası, ben genel EnumDescriptionCoverter kullanın: Biz türü her enum değeri kullanmak istemiyorsanız kullanışlıdır aşağıdaki:

<Window.Resources> 
    <ValueConverters:EnumDescriptionConverter x:Key="enumDescriptionConverter" /> 
</Window.Resources> 
... 
<ComboBox SelectedItem="{Binding UnitOfMeasure, Converter={StaticResource enumDescriptionConverter}}" 
      ItemsSource="{Binding VelocityUnitOfMeasureSelections, Mode=OneWay}" /> 
+0

Enum.Description() ve uzantı yöntemidir? Ben tip System.Enum üzerinde bu yöntemi bulamıyorum .. – mtijn

+0

.Description() açıklaması niteliğini alır bir uzantısı yöntemidir. Arka planda, DisplayName özniteliğini kullanmak daha uygun olabilirdi. –

+0

Sanırım bu atıfta edildi ve o (size nitelik kullanımını genişletmek sürece) alan hedefleri enum için geçerli değildir çünkü DisplayName kullanılmaz muhtemelen neydi, soru vücuttaki uzatma yöntemini gözden kaçan – mtijn

0

böyle yaptık:

<ComboBox x:Name="CurrencyCodeComboBox" Grid.Column="4" DisplayMemberPath="." HorizontalAlignment="Left" Height="22" Margin="11,6.2,0,10.2" VerticalAlignment="Center" Width="81" Grid.Row="1" SelectedValue="{Binding currencyCode}" > 
      <ComboBox.ItemsPanel> 
       <ItemsPanelTemplate> 
        <VirtualizingStackPanel/> 
       </ItemsPanelTemplate> 
      </ComboBox.ItemsPanel> 
     </ComboBox> 
0 kodunda

Ben ItemSource ayarlayın:

CurrencyCodeComboBox.ItemsSource = [Enum].GetValues(GetType(currencyCode))