Databinding an enum property to a ComboBox in WPF

后端 未结 13 1355
北海茫月
北海茫月 2020-11-22 15:46

As an example take the following code:

public enum ExampleEnum { FooBar, BarFoo }

public class ExampleClass : INotifyPropertyChanged
{
    private ExampleEn         


        
相关标签:
13条回答
  • 2020-11-22 16:13

    Try using

    <ComboBox ItemsSource="{Binding Source={StaticResource ExampleEnumValues}}"
        SelectedValue="{Binding Path=ExampleProperty}" />
    
    0 讨论(0)
  • 2020-11-22 16:14

    Here is a generic solution using a helper method. This can also handle an enum of any underlying type (byte, sbyte, uint, long, etc.)

    Helper Method:

    static IEnumerable<object> GetEnum<T>() {
        var type    = typeof(T);
        var names   = Enum.GetNames(type);
        var values  = Enum.GetValues(type);
        var pairs   =
            Enumerable.Range(0, names.Length)
            .Select(i => new {
                    Name    = names.GetValue(i)
                ,   Value   = values.GetValue(i) })
            .OrderBy(pair => pair.Name);
        return pairs;
    }//method
    

    View Model:

    public IEnumerable<object> EnumSearchTypes {
        get {
            return GetEnum<SearchTypes>();
        }
    }//property
    

    ComboBox:

    <ComboBox
        SelectedValue       ="{Binding SearchType}"
        ItemsSource         ="{Binding EnumSearchTypes}"
        DisplayMemberPath   ="Name"
        SelectedValuePath   ="Value"
    />
    
    0 讨论(0)
  • 2020-11-22 16:18

    This is a DevExpress specific answer based on the top-voted answer by Gregor S. (currently it has 128 votes).

    This means we can keep the styling consistent across the entire application:

    enter image description here

    Unfortunately, the original answer doesn't work with a ComboBoxEdit from DevExpress without some modifications.

    First, the XAML for the ComboBoxEdit:

    <dxe:ComboBoxEdit ItemsSource="{Binding Source={xamlExtensions:XamlExtensionEnumDropdown {x:myEnum:EnumFilter}}}"
        SelectedItem="{Binding BrokerOrderBookingFilterSelected, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
        DisplayMember="Description"
        MinWidth="144" Margin="5" 
        HorizontalAlignment="Left"
        IsTextEditable="False"
        ValidateOnTextInput="False"
        AutoComplete="False"
        IncrementalFiltering="True"
        FilterCondition="Like"
        ImmediatePopup="True"/>
    

    Needsless to say, you will need to point xamlExtensions at the namespace that contains the XAML extension class (which is defined below):

    xmlns:xamlExtensions="clr-namespace:XamlExtensions"
    

    And we have to point myEnum at the namespace that contains the enum:

    xmlns:myEnum="clr-namespace:MyNamespace"
    

    Then, the enum:

    namespace MyNamespace
    {
        public enum EnumFilter
        {
            [Description("Free as a bird")]
            Free = 0,
    
            [Description("I'm Somewhat Busy")]
            SomewhatBusy = 1,
    
            [Description("I'm Really Busy")]
            ReallyBusy = 2
        }
    }
    

    The problem in with the XAML is that we can't use SelectedItemValue, as this throws an error as the setter is unaccessable (bit of an oversight on your part, DevExpress). So we have to modify our ViewModel to obtain the value directly from the object:

    private EnumFilter _filterSelected = EnumFilter.All;
    public object FilterSelected
    {
        get
        {
            return (EnumFilter)_filterSelected;
        }
        set
        {
            var x = (XamlExtensionEnumDropdown.EnumerationMember)value;
            if (x != null)
            {
                _filterSelected = (EnumFilter)x.Value;
            }
            OnPropertyChanged("FilterSelected");
        }
    }
    

    For completeness, here is the XAML extension from the original answer (slightly renamed):

    namespace XamlExtensions
    {
        /// <summary>
        ///     Intent: XAML markup extension to add support for enums into any dropdown box, see http://bit.ly/1g70oJy. We can name the items in the
        ///     dropdown box by using the [Description] attribute on the enum values.
        /// </summary>
        public class XamlExtensionEnumDropdown : MarkupExtension
        {
            private Type _enumType;
    
    
            public XamlExtensionEnumDropdown(Type enumType)
            {
                if (enumType == null)
                {
                    throw new ArgumentNullException("enumType");
                }
    
                EnumType = enumType;
            }
    
            public Type EnumType
            {
                get { return _enumType; }
                private set
                {
                    if (_enumType == value)
                    {
                        return;
                    }
    
                    var enumType = Nullable.GetUnderlyingType(value) ?? value;
    
                    if (enumType.IsEnum == false)
                    {
                        throw new ArgumentException("Type must be an Enum.");
                    }
    
                    _enumType = value;
                }
            }
    
            public override object ProvideValue(IServiceProvider serviceProvider)
            {
                var enumValues = Enum.GetValues(EnumType);
    
                return (
                    from object enumValue in enumValues
                    select new EnumerationMember
                           {
                               Value = enumValue,
                               Description = GetDescription(enumValue)
                           }).ToArray();
            }
    
            private string GetDescription(object enumValue)
            {
                var descriptionAttribute = EnumType
                    .GetField(enumValue.ToString())
                    .GetCustomAttributes(typeof (DescriptionAttribute), false)
                    .FirstOrDefault() as DescriptionAttribute;
    
    
                return descriptionAttribute != null
                    ? descriptionAttribute.Description
                    : enumValue.ToString();
            }
    
            #region Nested type: EnumerationMember
            public class EnumerationMember
            {
                public string Description { get; set; }
                public object Value { get; set; }
            }
            #endregion
        }
    }
    

    Disclaimer: I have no affiliation with DevExpress. Telerik is also a great library.

    0 讨论(0)
  • 2020-11-22 16:20

    I've created an open source CodePlex project that does this. You can download the NuGet package from here.

    <enumComboBox:EnumComboBox EnumType="{x:Type demoApplication:Status}" SelectedValue="{Binding Status}" />
    
    0 讨论(0)
  • 2020-11-22 16:23

    I don't know if it is possible in XAML-only but try the following:

    Give your ComboBox a name so you can access it in the codebehind: "typesComboBox1"

    Now try the following

    typesComboBox1.ItemsSource = Enum.GetValues(typeof(ExampleEnum));
    
    0 讨论(0)
  • 2020-11-22 16:25

    If you are using a MVVM, based on @rudigrobler answer you can do the following:

    Add the following property to the ViewModel class

    public Array ExampleEnumValues => Enum.GetValues(typeof(ExampleEnum));
    

    Then in the XAML do the following:

    <ComboBox ItemsSource="{Binding ExampleEnumValues}" ... />
    
    0 讨论(0)
提交回复
热议问题