How To Bind a Combobox to a Dictionary in WPF C#

2019-09-17 10:32发布

I'm trying to bind a combobox to a dictionary and display a specific field within the currently selected object in WPF.

What I want displayed in the combobox: ("I will do it" is initally selected)
I will do it
I will not do it
I might do it

What is actually displayed currently: (nothing is initally selected)
[YES, AnswerDisplayItem]
[No, AnswerDisplayItem]
[MAYBE, AnswerDisplayItem]

Here's my code:

public enum Answer { YES, NO, MAYBE}

public class AnswerDisplayItem
{
    public string DisplayName { get; }
    public string DisplayDescription { get; }
    public AnswerDisplayItem(string displayName, string displayDescription)
    {
        DisplayName = displayName;
        DisplayDescription = displayDescription;
    }
}


public class MyViewModel()
{
    public MyViewModel() 
    {
        AnswerDisplay = new Dictionary<Answer, AnswerDisplayItem>
        {
            {Answer.YES, new AnswerDisplayItem("Yes", "I will do it") },
            {Answer.NO, new AnswerDisplayItem("No", "I will not do it")},
            {Answer.MAYBE, new AnswerDisplayItem("Maybe", "I might do it")}
        };
        SelectedAnswer = Answer.Yes;
    }


    public Dictionary<Answer, AnswerDisplayItem> AnswerDisplay{ get; private set; }

    private Answer _selectedAnswer;
    public Answer SelectedAnswer
    {
        get
        {
            return _selectedAnswer;
        }
        set
        {
            if (_selectedAnswer != value)
            {
                _selectedAnswer = value;
                RaisePropertyChanged();
            }
        }
    }
}

XAML:

<ComboBox ItemsSource="{Binding AnswerDisplay}" 
          DisplayMemberPath="Value.DisplayDescription"
          SelectedItem="{Binding SelectedAnswer}"/>

2条回答
劫难
2楼-- · 2019-09-17 10:58

Use a Dictionary<Answer,string> (no need for another class)

AnswerDisplay = new Dictionary<Answer, string>
{
    {Answer.YES, "I will do it"},
    {Answer.NO,  "I will not do it"},
    {Answer.MAYBE, "I might do it"},
};

and bind it to the ComboBox

<ComboBox ItemsSource="{Binding AnswerDisplay}" 
          DisplayMemberPath="Value"
          SelectedValuePath="Key"
          SelectedValue="{Binding SelectedAnswer}"/>

Update

If you want to use your dictionary, then change the binding to

<ComboBox ItemsSource="{Binding AnswerDisplay}" 
          DisplayMemberPath="Value.DisplayDescription"
          SelectedValuePath="Key"
          SelectedValue="{Binding SelectedAnswer}"/>
查看更多
老娘就宠你
3楼-- · 2019-09-17 11:10

The desired functionality can be easily achieved by binding to key value property generated from enum:

Define the enum:

 public enum DateModes
{
    [Description("DAYS")]
    Days,
    [Description("WKS")]
    Weeks,
    [Description("MO")]
    Month,
    [Description("YRS")]
    Years
 }

The following helper method will return the KeyValue pairs

 public static string Description(this Enum eValue)
    {
        var nAttributes = eValue.GetType().GetField(eValue.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
        if (nAttributes.Any())
        {
            var descriptionAttribute = nAttributes.First() as DescriptionAttribute;
            if (descriptionAttribute != null)
                return descriptionAttribute.Description;
        }

        // If no description is found, the least we can do is replace underscores with spaces
        TextInfo oTI = CultureInfo.CurrentCulture.TextInfo;
        return oTI.ToTitleCase(oTI.ToLower(eValue.ToString().Replace("_", " ")));
    }     
public static IEnumerable<KeyValuePair<string, string>> GetAllValuesAndDescriptions<TEnum>() where TEnum : struct, IConvertible, IComparable, IFormattable
    {
        if (!typeof(TEnum).IsEnum)
        {
            throw new ArgumentException("TEnum must be an Enumeration type");
        }

        return from e in Enum.GetValues(typeof(TEnum)).Cast<Enum>()
               select new KeyValuePair<string, string>(e.ToString(), e.Description());
    }

Property in the ViewModel (or DataContext):

public IEnumerable<KeyValuePair<string, string>> DateModes { get { return EnumHelper.GetAllValuesAndDescriptions<DateModes>(); } }

Binding in the View:

                  <ComboBox 
                      ItemsSource="{Binding DateModes}"
                      SelectedValue="{Binding SelectedDateDisplay}"
                      DisplayMemberPath="Value"
                      SelectedValuePath="Key"
                      VerticalAlignment="Top"/>

What you want to display is nothing but the description attribute of the enum. I feel this method will be a lot cleaner.

查看更多
登录 后发表回答