首页 > 技术文章 > WPF -Enum的三种绑定方法

HQFZ 2015-08-11 11:36 原文

一、使用ObjectDataProvider

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:sys="clr-namespace:System;assembly=mscorlib"
  SizeToContent="WidthAndHeight"
  Title="Show Enums in a ListBox using Binding">
 
  <Window.Resources>
    <ObjectDataProvider MethodName="GetValues"
                        ObjectType="{x:Type sys:Enum}"
                        x:Key="AlignmentValues">
      <ObjectDataProvider.MethodParameters>
        <x:Type TypeName="HorizontalAlignment" />
      </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
  </Window.Resources>
 
  <Border Margin="10" BorderBrush="Aqua"
          BorderThickness="3" Padding="8">
    <StackPanel Width="300">
      <TextBlock>Choose the HorizontalAlignment
                 value of the Button:</TextBlock>
      <ListBox Name="myComboBox" SelectedIndex="0" Margin="8"
               ItemsSource="{Binding Source={StaticResource
                                             AlignmentValues}}"/>
      <Button Content="Click Me!"
              HorizontalAlignment="{Binding ElementName=myComboBox,
                                            Path=SelectedItem}"/>
    </StackPanel>
  </Border>
</Window>

BindToEnum

 

二、使用Converter

public class RadioButtonCheckedConverter: IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, 
        System.Globalization.CultureInfo culture)
    {
        return value.Equals(parameter);
    }

    public object ConvertBack(object value, Type targetType, object parameter, 
        System.Globalization.CultureInfo culture)
    {
        return value.Equals(true) ? parameter : Binding.DoNothing;
    }
}
使用方法:
<RadioButton GroupName="EnumGroup"
    IsChecked="{Binding EnumProperty, Converter={StaticResource RadioButtonCheckedConverter}, 
    ConverterParameter={x:Static src:TestEnum.Option1}}">
</RadioButton>

<RadioButton GroupName="EnumGroup"  
    IsChecked="{Binding EnumProperty, Converter={StaticResource RadioButtonCheckedConverter}, 
    ConverterParameter={x:Static src:TestEnum.Option2}}">
</RadioButton>

<RadioButton GroupName="EnumGroup"  
    IsChecked="{Binding EnumProperty, Converter={StaticResource RadioButtonCheckedConverter}, 
    ConverterParameter={x:Static src:TestEnum.Option3}}">
</RadioButton>
 

三、使用扩展的Markup

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

   }

}
 
使用方法:
<ListBox Name="myComboBox" SelectedIndex="0" Margin="8"

              ItemsSource="{my:EnumValues HorizontalAlignment}"/>

四、使用资源文件实现Enum本地化

为Enum类型自定义Attribute

从而实现Enum与资源关联

    /// <summary>
    /// Attribute for localization.
    /// </summary>
    [AttributeUsage(AttributeTargets.All,Inherited = false,AllowMultiple = true)]
    public sealed class LocalizableDescriptionAttribute : DescriptionAttribute
    {
        #region Public methods.
        // ------------------------------------------------------------------

        /// <summary>
        /// Initializes a new instance of the 
        /// <see cref="LocalizableDescriptionAttribute"/> class.
        /// </summary>
        /// <param name="description">The description.</param>
        /// <param name="resourcesType">Type of the resources.</param>
        public LocalizableDescriptionAttribute
		(string description,Type resourcesType) : base(description)
        {
            _resourcesType = resourcesType;
        }

        #endregion

        #region Public properties.

        /// <summary>
        /// Get the string value from the resources.
        /// </summary>
        /// <value></value>
        /// <returns>The description stored in this attribute.</returns>
        public override string Description
        {
            get
            {
                if (!_isLocalized)
                {
                    ResourceManager resMan =
                         _resourcesType.InvokeMember(
                         @"ResourceManager",
                         BindingFlags.GetProperty | BindingFlags.Static |
                         BindingFlags.Public | BindingFlags.NonPublic,
                         null,
                         null,
                         new object[] { }) as ResourceManager;

                    CultureInfo culture =
                         _resourcesType.InvokeMember(
                         @"Culture",
                         BindingFlags.GetProperty | BindingFlags.Static |
                         BindingFlags.Public | BindingFlags.NonPublic,
                         null,
                         null,
                         new object[] { }) as CultureInfo;

                    _isLocalized = true;

                    if (resMan != null)
                    {
                        DescriptionValue =
                             resMan.GetString(DescriptionValue, culture);
                    }
                }

                return DescriptionValue;
            }
        }
        #endregion

        #region Private variables.

        private readonly Type _resourcesType;
        private bool _isLocalized;

        #endregion
    }

实现自定义的Converter

    /// <summary>
    /// This class simply takes an enum and uses some reflection to obtain
    /// the friendly name for the enum. Where the friendlier name is
    /// obtained using the LocalizableDescriptionAttribute, which holds the localized
    /// value read from the resource file for the enum
    /// </summary>
    [ValueConversion(typeof(object), typeof(String))]
    public class EnumToFriendlyNameConverter : IValueConverter
    {
        #region IValueConverter implementation

        /// <summary>
        /// Convert value for binding from source object
        /// </summary>
        public object Convert(object value, Type targetType,
                object parameter, CultureInfo culture)
        {
            // To get around the stupid WPF designer bug
            if (value != null)
            {
                FieldInfo fi = value.GetType().GetField(value.ToString());

                // To get around the stupid WPF designer bug
                if (fi != null)
                {
                    var attributes =
                        (LocalizableDescriptionAttribute[]) 
			fi.GetCustomAttributes(typeof 
			(LocalizableDescriptionAttribute), false);

                    return ((attributes.Length > 0) &&
                            (!String.IsNullOrEmpty(attributes[0].Description)))
                               ?
                                   attributes[0].Description
                               : value.ToString();
                }
            }

            return string.Empty;
        }

        /// <summary>
        /// ConvertBack value from binding back to source object
        /// </summary>
        public object ConvertBack(object value, Type targetType, 
			object parameter, CultureInfo culture)
        {
            throw new Exception("Cant convert back");
        }
        #endregion
    }

使用方法:

<ComboBox x:Name="cmbFoodType"  
    ItemsSource="{Binding Source={StaticResource foodData}}"
    SelectedItem="{Binding Path=TestableClass.FoodType, Mode=TwoWay}" Height="Auto">
    <ComboBox.ItemTemplate>

        <DataTemplate>
            <Label  Content="{Binding   Path=.,Mode=OneWay, 
                                Converter={StaticResource enumItemsConverter}}"
                    Height="Auto"
                    Margin="0" 
                    VerticalAlignment="Center"/>

        </DataTemplate>
    </ComboBox.ItemTemplate>
</ComboBox>

参考

Binding and Using Friendly Enums in WPF

Displaying Enum Values using Data Binding

Binding Radio Buttons to a Single Property

推荐阅读