2013-02-22 32 views
5

Tôi có kịch bản sau đây: Tôi có một enum, và muốn ràng buộc nó hiển thị nó trong một DataGridView (databound) trên một DataGridViewTextBoxColumn.Ràng buộc một TypeConverter trực tiếp vào một liệt kê

Đây là enum của tôi:

//[TypeConverter(typeof(EnumStringConverter))] 
    public enum YesNoNA 
    { 
     [EnumDescription("Yes")] 
     Yes, 
     [EnumDescription("No")] 
     No, 
     [EnumDescription("N/A")] 
     NA 
    } 

Và đây là một tài sản đơn giản mà sử dụng nó:

[TypeConverter(typeof(EnumStringConverter))] 
    public YesNoNA HighLimitWithinBounds { get; protected set; } 

Trong tình hình tôi có ở trên, typeconverter làm việc tốt. Nó chuyển đổi cho tôi.

Tuy nhiên, điều này phức tạp hơn giải pháp lý tưởng của tôi. Nếu tôi đặt typeconverter trên chính Enum (uncomment đoạn code ở trên), và nhận xét ra các typeconverter về tài sản, các typeconverter không còn được gọi là!

Tôi đã thực hiện quy ước này trên các lớp khác và nó hoạt động tốt.

Tại sao việc đặt một trình gõ trực tiếp trên một enum không hoạt động?

Để tham khảo, đây là typeconverter tôi:

public class EnumStringConverter : TypeConverter 
    { 
     public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, Object value, Type destinationType) 
     { 
     if (value != null && destinationType == typeof(string)) 
     { 
      return "Edited to protect the innocent!"; 
     } 
     return TypeDescriptor.GetConverter(typeof(Enum)).ConvertTo(context, culture, value, destinationType); 
     } 
     public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType) 
     { 
     if (destinationType == typeof(string)) 
     { 
      return true; 
     } 
     return base.CanConvertTo(context, destinationType); 
     } 
    }; 
+1

Có lẽ bạn nên thử phương pháp này: http://en.wikipedia.org/wiki/Rubber_duck_debugging – espais

+0

bản sao có thể có của [Làm cách nào để ghi đè ToString trong C# enums?] (Http://stackoverflow.com/questions/796607/how-do-i-override-tostring-in-c-sharp-enums) –

+0

Không liên quan rõ ràng. Giải pháp cho câu trả lời trong chuỗi đó đã được triển khai ở trên. Câu hỏi này đang tiến xa hơn nhiều. – greggorob64

Trả lời

2

Tôi không chắc chắn những gì bạn có ý nghĩa bởi "đây là phức tạp hơn so với giải pháp lý tưởng của tôi". Tôi có một cách để làm điều này khác với bạn nhưng nó có thể không kém phức tạp. Tôi sẽ nói theo cách của tôi liên quan đến chi phí nhiều hơn lên phía trước nhưng trả hết càng nhiều bạn sử dụng nó trong ứng dụng của bạn. Nó chuẩn bị ứng dụng của bạn để được bản địa hóa và có nghĩa là bạn không phải thêm các thuộc tính vào mỗi giá trị enum.

1) Thực hiện một bộ nhớ cache Resource Manager

phần này không bắt buộc; tuy nhiên nếu bạn sử dụng nhiều tệp tài nguyên nhiều lần như tôi làm điều này có thể tăng hiệu suất bằng cách giảm mức độ phản ánh được thực hiện.

using System; 
using System.Collections.Generic; 
using System.Reflection; 
using System.Resources; 

namespace AppResourceLib.Public.Reflection 
{ 
    internal static class ResourceManagerCache 
    { 
    private static Dictionary<Type, ResourceManager> _resourceManagerMap = 
     new Dictionary<Type, ResourceManager>(); 

    public static ResourceManager GetResourceManager(Type resourceType) 
    { 
     ResourceManager resourceManager = null; 

     // Make sure the type is valid. 
     if (null != resourceType) 
     { 
     // Try getting the cached resource manager. 
     if (!ResourceManagerCache._resourceManagerMap.TryGetValue(resourceType, out resourceManager)) 
     { 
      // If it is not in the cache create it. 
      resourceManager = resourceType.InvokeMember(
      "ResourceManager", 
      (BindingFlags.GetProperty | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic), 
      null,             
      null,             
      null) as ResourceManager; 

      // If it was created, add the resource manager to the cache. 
      if (null != resourceManager) 
      { 
      ResourceManagerCache._resourceManagerMap.Add(resourceType, resourceManager); 
      } 
     } 
     } 

     return resourceManager; 
    } 
    } 
} 

2) Tạo Mô tả Thuộc tính Localized

Đây là thuộc tính mà bạn sẽ áp dụng cho các loại Enum. Điều thú vị về điều này là bạn không phải thêm một thuộc tính cho mỗi enum, chỉ một lần trên khai báo kiểu enum.

using System; 
using System.ComponentModel; 

namespace AppResourceLib.Public.Reflection 
{ 
    /// <summary> 
    /// A resource type attribute that can be applied to enumerations. 
    /// </summary> 
    [AttributeUsage(AttributeTargets.Enum)] 
    public sealed class LocalizedDescriptionAttribute : Attribute 
    { 
    /// <summary> 
    /// The type of resource associated with the enum type. 
    /// </summary> 
    private Type _resourceType; 

    public LocalizedDescriptionAttribute(Type resourceType) 
    { 
     this._resourceType = resourceType; 
    } 

    /// <summary> 
    /// The type of resource associated with the enum type. 
    /// </summary> 
    public Type ResourceType 
    { 
     get 
     { 
     return this._resourceType; 
     } 
    } 
    } 
} 

3) Tạo địa hoá Mô tả Chuyển đổi

này chuyển giá trị enum vào chuỗi bạn sẽ cung cấp cho nó trong chuỗi nguồn (Resx) tập tin.

using System; 
using System.Globalization; 
using System.Linq; 
using System.Reflection; 
using System.Resources; 
using System.Windows.Data; 

namespace AppResourceLib.Public.Reflection 
{ 
    [ValueConversion(typeof(Object), typeof(String))] 
    public class LocalizedDescriptionConverter : IValueConverter 
    { 
    public Object Convert(Object value, Type targetType, Object param, CultureInfo cultureInfo) 
    { 
     String description = null; 

     if (null != value) 
     { 
     // If everything fails then at least return the value.ToString(). 
     description = value.ToString(); 

     // Get the LocalizedDescriptionAttribute of the object. 
     LocalizedDescriptionAttribute attribute = 
      value.GetType().GetCustomAttribute(typeof(LocalizedDescriptionAttribute)) 
      as LocalizedDescriptionAttribute; 

     // Make sure we found a LocalizedDescriptionAttribute. 
     if (null != attribute) 
     {   
      ResourceManager resourceManager = 
      ResourceManagerCache.GetResourceManager(attribute.ResourceType); 

      if (null != resourceManager) 
      { 
      // Use the ResourceManager to get the description you gave the object value. 
      // Here we just use the object value.ToString() (the name of the object) to get 
      // the string in the .resx file. The only constraint here is that you have to 
      // name your object description strings in the .resx file the same as your objects. 
      // The benefit is that you only have to declare the LocalizedDescriptionAttribute 
      // above the object type, not an attribute over every object. 
      // And this way is localizable. 
      description = resourceManager.GetString(value.ToString(), cultureInfo); 

      String formatString = (param as String); 

      // If a format string was passed in as a parameter, 
      // make a string out of that. 
      if (!String.IsNullOrEmpty(formatString)) 
      { 
       formatString = formatString.Replace("\\t", "\t"); 
       formatString = formatString.Replace("\\n", "\n"); 
       formatString = formatString.Replace("\\r", "\r"); 

       description = String.Format(formatString, value.ToString(), description);    
      }   
      } 
     } 
     } 

     return description;  
    } 

    public Object ConvertBack(Object value, Type targetType, Object param, CultureInfo cultureInfo) 
    { 
     throw new NotImplementedException(); 

     return null; 
     } 
    } 
} 

4) Tạo một tài nguyên (Resx) String tập

Bây giờ bạn muốn tạo một tập tin tài nguyên đó sẽ chứa các mô tả bạn muốn cho phong cách giá trị quan trọng Enums của bạn. Ý tôi là, trong cột "Tên" của tài nguyên chuỗi, bạn sẽ đặt tên chính xác của các enums riêng lẻ và trong cột "Value" bạn đặt chuỗi bạn muốn nhận khi chuyển đổi enum đó.
Ví dụ: giả sử bạn có các Enums sau đây.

public enum MyColors 
{ 
    Black, 
    Blue, 
    White 
} 

Sau đó, tập tin tài nguyên chuỗi của bạn sẽ trông như thế này ...

Tên | Giá trị

Đen | Màu tối
Màu xanh | Màu sắc mát mẻ
Trắng | Một màu Bright

5) Tạo Enums với Attribute

Bây giờ chúng ta cuối cùng đã thực hiện kê khai với LocalizedDescription Enum. Tham số mà bạn chuyển vào thuộc tính LocalizedDescription là loại tệp tài nguyên chuỗi của bạn. Bây giờ khi bộ chuyển đổi được sử dụng, nó sẽ thấy thuộc tính của kiểu enum, lấy tệp tài nguyên, tìm chuỗi khóa khớp với giá trị chuỗi của giá trị enum cụ thể và trả về giá trị từ tệp tài nguyên dưới dạng chuỗi được chuyển đổi.

using AppResourceLib.Public; 
using AppResourceLib.Public.Reflection; 

namespace MyEnums 
{ 
    [LocalizedDescription(typeof(MyColorStrings))] 
    public enum MyColors 
    { 
    Black, 
    Blue, 
    White 
    } 
} 

Hạn chế chính của phương pháp này là nó sẽ chỉ hoạt động nếu các khóa "Tên" trong tệp tài nguyên của bạn khớp với tên giá trị enum của bạn. Đây là cách duy nhất để tham chiếu các giá trị chuỗi trong một tệp tài nguyên mà không đưa ra mỗi enum một thuộc tính mô tả. Vậy làm thế nào để bạn sử dụng nó để hiển thị các giá trị? Dưới đây là ví dụ ...

Trong mã xaml của bạn, bạn sẽ muốn làm cho nhà cung cấp dữ liệu nhận được giá trị của enums cho phần tử giao diện người dùng của bạn (Tôi đang sử dụng ComboBox ở đây ...). Sau đó, bạn sẽ muốn làm cho trình biến đổi có sẵn và mẫu phần tử giao diện người dùng của bạn để sử dụng trình chuyển đổi enum. Vì vậy, ở đây nó đi ...

 <!-- Enum Colors --> 
    <ObjectDataProvider x:Key="MyColorEnums" 
         MethodName="GetValues" 
         ObjectType="{x:Type sys:Enum}"> 
    <ObjectDataProvider.MethodParameters> 
     <x:Type TypeName="MyColors"/> 
    </ObjectDataProvider.MethodParameters> 
    </ObjectDataProvider> 


    <!-- Enum Type Converter --> 
    <LocalizedDescriptionConverter x:Key="EnumConverter"/> 


    <!-- Dropdown Expand ComboBox Template --> 
    <DataTemplate x:Key="MyColorsComboBoxTemplate"> 
    <Label Content="{Binding Path=., Mode=OneWay, 
     Converter={StaticResource EnumConverter}}" 
      Height="Auto" Margin="0" VerticalAlignment="Center"/> 
    </DataTemplate> 

    <!-- And finally the ComboBox that will display all of your enum values 
    but will use the strings from the resource file instead of enum.ToString() --> 
    <ComboBox Width="80" HorizontalAlignment="Left" 
    ItemTemplate="{StaticResource MyColorsComboBoxTemplate}" 
    ItemsSource="{Binding Source={StaticResource MyColorEnums}}"> 

Rất tiếc, xin lỗi quá lâu. Tôi không chắc chắn nếu điều này là quá phức tạp cho bạn nhưng nó là một lựa chọn khác. Hy vọng nó giúp!

+1

Ví dụ của tôi rất giống với ví dụ của bạn (bạn tiến thêm một bước trong việc sử dụng tệp tài nguyên, mà tôi sử dụng ở những nơi khác cũng như để nhận hỗ trợ đa ngôn ngữ). Sự khác biệt về độ phức tạp mà tôi đề cập đến là ví dụ của tôi yêu cầu một công cụ gõ mã * Trên thuộc tính * thay vì trên chính enum. Rất tiếc, tôi không nghĩ rằng các ví dụ của chúng tôi sẽ khớp với nhau. Bạn đang sử dụng xaml và im sử dụng winforms thuần túy .net. Bạn đang dùng combobox của bạn. Xaml của bạn là đặc biệt ràng buộc combobox để chuyển đổi bạn cần, đó là những gì tôi đang cố gắng để tránh (tôi không nghĩ rằng tôi sẽ thành công). Cảm ơn bạn đã trả lời! – greggorob64

+0

Ồ, tôi hiểu ý của bạn là gì. Xin lỗi tôi không thể giúp. – akagixxer

Các vấn đề liên quan