2009-05-27 10 views
13

問題は私がこの列挙型を持っていることですが、コンボボックスに列挙型の値を表示させたくないということです。選択されたかActiveAndSelectedが、私は列挙型の値ごとにDescriptionPropertyを表示するコンボボックスの代わりに、アクティブ表示、でそうWPFバインディングコンボボックスからenumへ(ひねりあり)

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

:これが列挙型です。

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

だから私は、コンボボックスに列挙型をバインドし、それがのgetDescription拡張メソッドとの内容だ示すことができる方法がある:私は、列挙型のためのgetDescription(と呼ばれる拡張メソッド)を持っていますか?

ありがとうございます!

答えて

6

私はあなたの考え方が好きです。しかし、GetCustomAttributesはリフレクションを使用します。あなたのパフォーマンスにはどうなるでしょうか?

この記事をチェックアウト: WPF - ComboBoxコントロールでの列挙型にリフレクションを使用しての http://www.infosysblogs.com/microsoft/2008/09/wpf_displaying_enums_in_combob.html

+16

おい、反射は、特にそれがGUIを表示するのに要する時間に比べて、_that_遅いありません。私はそれが問題であるとは思わないでしょう。 –

+0

さて、私の言葉をそれに服用しないでください。上で参照された記事はそれが懸念だと言います。 –

+3

しかし、プロフィールの結果は引用しません。著者はそれについて心配していましたが、実際には問題ではありませんでした。 –

3

質問を表示し、脇の属性は、あなたがこれを行うことができますいくつかの方法がありますが、私は最善の方法はただにあると思います列挙値をラップ少しビューモデルクラスを作成します。

public class ModeViewModel : ViewModel 
{ 
    private readonly Mode _mode; 

    public ModeViewModel(Mode mode) 
    { 
     ... 
    } 

    public Mode Mode 
    { 
     get { ... } 
    } 

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

また、あなたがObjectDataProviderを使用しての中に見ることができます。

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

あなたはそのようにそれを使用することができます:

3

は、私はあなたがほんの少しの変更で、私はすでにhereを掲載していたマークアップ拡張機能を使用することをお勧めの方法Iを提案された文字列のリストにバインドされます。これは、SelectedItemをMode型にしたいので望ましくありません。 .Select(...)部分を削除し、ItemTemplateのカスタムコンバータでバインディングを使用する方がよいでしょう。

+0

これは、コンボボックスのSelectedItemをMode.Activeの代わりに "Display active only"にするのではないでしょうか?私に望ましくない副作用のように思えます。 –

+0

これは、この方法では、現在選択されている列挙型のオブジェクトに選択項目を設定できないことを意味しますか? – Carlo

+0

@ジョー:はい、そうです...それは本当に問題です。私は答えを更新する –

19

私はDataTemplateとValueConverterを提案します。これにより、表示方法をカスタマイズできますが、コンボボックスのSelectedItemプロパティを読み取って実際の列挙値を取得することはできます。

ValueConvertersには定型コードがたくさん必要ですが、ここでは複雑すぎるものはありません。まず、あなたがValueConverterクラスを作成します。

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

あなただけ(ディスプレイ用)文字列に列挙値を変換しているので、あなたはConvertBackを必要としない - それはちょうど2ウェイバインディングのシナリオのためです。

は、その後、あなたがこのようなもので、あなたのリソースにValueConverterのインスタンスを置く:

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

を次に、コンボボックスにModeConverterを使用して、そのアイテムをフォーマットDisplayTemplateを与えるために準備が整いました

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

これをテストするために、私は実際のSelectedItem値を表示するラベルを投げましたが、実際にはSelectedItemが表示テキストの代わりに列挙型であることを示しています。

<Label Content="{Binding ElementName=comboBox, Path=SelectedItem}"/> 
+0

おい、あなたの答えは最終的にインターネットの掘削の数時間後に私の問題を解決しました。ありがとう! – mcy

6

これは私がMVVMでやっている方法です。私のモデルでは、私は私の列挙型を定義しているだろう:私のViewModelに

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

私は、文字列だけでなく、/モデルの値を設定し取得するためのプロパティとして可能な選択を提供してプロパティを公開します。私たちは種類で、すべての列挙値を使用したくない場合に便利です:

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

さらに、私は一般的なEnumDescriptionCoverter使用:

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

そして最後に、ビューと私にできること次

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

はEnum.Description()と拡張メソッドですか? System.Enum型でそのメソッドを見つけることができません。 – mtijn

+0

.Description()はdescription属性を取得する拡張メソッドです。後で見ると、DisplayName属性を使用するほうが適切かもしれません。 –

+0

私は質問本体の拡張メソッドを見落としました。これはおそらくあなたが参照していたもので、DisplayNameは列挙型フィールドのターゲットには適用されないため使用されません。(属性の使用を展開しない限り) – mtijn

0

私はこのようにそれをやった:

<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コード内

私はitemSourceを設定:

CurrencyCodeComboBox.ItemsSource = [Enum].GetValues(GetType(currencyCode)) 
関連する問題