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}"/>
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}"/>
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.