2016-10-27 8 views
1

enumで単一の属性を使用するという現代的な解決策を探しているうちに、エントリの表示名とツールチップのデータを提供する私はseveralquestionsanswershereにつきました。enum属性を取得する一般的な方法(i18n /ローカライゼーションサポートあり)

しかし、それはa)のが属性内ResourceType = typeof(<YourResourcesFileType, e. g. "Resources">と拡張メソッドとB内ResourceManagerのインスタンス)を使用して、正しい方向に私を指摘は、この別の質問を書くために私を奨励することをthis特定の回答だったと答えも。

ここで、より新しいC#言語機能を利用してeを実装する、良い、好ましくは一般的なアプローチを書く方法を教えてください。 g。 enumエントリごとに1つの属性のみを使用して、各エントリのツールチップを提供しながらデータをドロップダウンしますか?それも可能ですか?

答えは:DisplayAttributeを使用して、そのNameDescriptionの特性を活用することでYES

私はWPFアプリケーション用に開発して以来、私はMVVMに縛られていて、可能な限りきれいで読みやすいコードを目指していました。しかし、すべてのコードと同様に、常に改善の余地があります。ですから、これをさらに改善できると思ったら、ご意見をお寄せください。

+0

それはあなたがすべてが保存されている場合、属性必要ない理由SO – Lithium

+0

@Yoda、ドキュメントのセクションのエントリとしてよく合うのと同じように見えます。これは、リソースで?列挙型フィールド名(例: 'QuestionType.Answer')は、Resourceの良いキーです。 '_Entry'または' _ToolTip'は、キー( 'QuestionType.Answer_ToolTip')に追加してパラメータとしてconverterに渡すことができる規約です。 [Enumローカリゼーションの私のバリエーション - EnumLocalizationConverter](https://github.com/AlexanderSharykin/CardIdleRemastered/blob/master/SourceCode/CardIdleRemastered/Converters/EnumLocalizationConverter.cs)(任意のEnumで動作します) – ASh

+0

@Lithiumあなたはこれを達成する方法を示すいくつかのガイド? – Yoda

答えて

0

注:コードはSOのデザインに合うようにフォーマットされていますが、一般的なC#ライン(ブレーク)デザインではなく、水平スクロールが嫌いです。

リソースファイル、Resources.resxResources.resx example

注#1:あなたがするために公開アクセス修飾子(上のスクリーンショットでは右上隅)を設定する必要があります。私の場合に必要な他のアセンブリからのアクセスを取得します。 #2

注:多言語サポートのVisual Studioのの概念を活用する、ローカライズされたリソースファイルは、Resources.xx-XX.resx、電子名前を付ける必要があります。 g。 Resources.de-DE.resx。

enum

QuestionType.csEnumExtensions.cs

namespace Yoda.Data.Interfaces.Enums 
{ 
    using System.ComponentModel.DataAnnotations; 
    using Yoda.Data.Interfaces.Properties; 

    public enum QuestionType 
    { 
    [Display(Name = "Question_Type_Unknown_Entry", 
      ResourceType = typeof(Resources), 
      Description = "Question_Type_Unknown_ToolTip")] 
    Unknown = 0, 

    [Display(Name = "Question_Type_Question_Entry", 
      ResourceType = typeof(Resources), 
      Description = "Question_Type_Question_ToolTip")] 
    Question = 1, 

    [Display(Name = "Question_Type_Answer_Entry", 
      ResourceType = typeof(Resources), 
      Description = "Question_Type_Answer_ToolTip")] 
    Answer = 2 
    } 
} 

拡張メソッド(複数可):

namespace Yoda.Frontend.Extensions 
{ 
    using System; 
    using System.ComponentModel.DataAnnotations; 
    using System.Globalization; 
    using System.Linq; 
    using System.Resources; 

    public static class EnumExtensions 
    { 
    // This method can be made private if you don't use it elsewhere 
    public static TAttribute GetEnumAttribute<TAttribute>(this Enum enumValue) 
     where TAttribute : Attribute 
    { 
     var memberInfo = enumValue.GetType().GetMember(enumValue.ToString()); 

     return memberInfo[0].GetCustomAttributes(typeof(TAttribute), false) 
          .OfType<TAttribute>() 
          .FirstOrDefault(); 
    } 

    public static string ToDescription(this Enum enumValue) 
    { 
     var displayAttribute = enumValue.GetEnumAttribute<DisplayAttribute>(); 

     return displayAttribute == null 
     ? enumValue.ToString().Replace("_", " ") 
     : new ResourceManager(displayAttribute.ResourceType) 
       .GetString(displayAttribute.Description, CultureInfo.CurrentUICulture); 
    } 

    public static string ToName(this Enum enumValue) 
    { 
     var displayAttribute = enumValue.GetEnumAttribute<DisplayAttribute>(); 

     return displayAttribute == null 
     ? enumValue.ToString().Replace("_", " ") 
     : new ResourceManager(displayAttribute.ResourceType) 
       .GetString(displayAttribute.Name, CultureInfo.CurrentUICulture); 
    } 
    } 

    // Your other enum extension methods go here... 
} 

2つのコンバータを必要とWPFで使用例( SoCに従うようにすると、次のようになります。

NameプロパティコンバーターQuestionTypeNameConverter。CS

namespace Yoda.Frontend.Converters 
{ 
    using System; 
    using System.Globalization; 
    using System.Windows.Data; 

    using Yoda.Data.Interfaces.Enums; 
    using Yoda.Frontend.Extensions; 

    // Second converter would be named QuestionTypeDescriptionConverter 
    public class QuestionTypeNameConverter : IValueConverter 
    { 
    public object Convert(object value, Type targetType, object parameter, 
          CultureInfo culture) 
    { 
     // Second converter would call .ToDescription() instead 
     return (value as QuestionType? ?? QuestionType.Unknown).ToName(); 
    } 

    public object ConvertBack(object value, Type targetType, object parameter, 
           CultureInfo culture) 
    { 
     return value; 
    } 
    } 
} 

注:唯一のコンバータクラスを表示するためにあなたの読書の喜びのためは、私は私の例を制限するんだけど、私は2番目の1のために必要な変更を説明するコメントを含めました。

そして最後にMainView.xamlでの使用:

<Window x:Class="Yoda.Frontend.MainView" x:Name="MainWindow"> 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

     // ... more xmlns & other basic stuff 

     xmlns:c="clr-namespace:CAP.GUI.Converters" 
    <Window.Resources> 
    <c:QuestionTypeDescriptionConverter x:Key="QuestionTypeDescription" /> 
    <c:QuestionTypeNameConverter  x:Key="QuestionTypeName" /> 
    </Window.Resources> 

    // Your window layout goes here... 

    <ComboBox ItemsSource="{Binding QuestionTypes, Mode=OneWay}" Margin="3" Name="QuestionType" 
      SelectedItem="{Binding SelectedItem.ValidQuestionType, 
            Converter={StaticResource QuestionTypeName}}" 
      ToolTip="{Binding SelectedItem.ValidQuestionType, 
           Converter={StaticResource QuestionTypeDescription}}"> 
    <ComboBox.ItemTemplate> 
     <DataTemplate> 
     <TextBlock Text="{Binding Converter={StaticResource QuestionTypeName}}" 
        ToolTip="{Binding Converter={StaticResource QuestionTypeDescription}}" /> 
     </DataTemplate> 
    </ComboBox.ItemTemplate> 
    </ComboBox> 

    // Your other window layout goes here... 

</Window> 
関連する問題