मुझे उन सभी वस्तुओं के लिए पसंद है जिन्हें मैं अपने में परिभाषित करने के लिए बाध्य कर रहा हूं ViewModel, इसलिए <ObjectDataProvider>जब संभव हो तो मैं xaml के उपयोग से बचने की कोशिश करता हूं ।
मेरा समाधान दृश्य में परिभाषित कोई डेटा और कोई कोड-पीछे का उपयोग करता है। केवल एक DataBinding, एक पुन: प्रयोज्य ValueConverter, किसी भी Enum प्रकार के लिए विवरण का एक संग्रह प्राप्त करने के लिए एक विधि, और देखने के लिए बाइंड करने के लिए ViewModel में एक एकल गुण।
जब मैं Enumकिसी ComboBoxऐसे पाठ में बाँधना चाहता हूँ जिसे मैं प्रदर्शित करना चाहता हूँ, के मूल्यों से कभी मेल नहीं खाता है Enum, इसलिए मैं [Description()]इसे उस पाठ को देने के लिए विशेषता का उपयोग करता हूँ जिसे मैं वास्तव में देखना चाहता हूँ ComboBox। यदि मेरे पास सप्ताह के दिनों की एक पहेली है, तो यह कुछ इस तरह दिखाई देगा:
public enum DayOfWeek
{
// add an optional blank value for default/no selection
[Description("")]
NOT_SET = 0,
[Description("Sunday")]
SUNDAY,
[Description("Monday")]
MONDAY,
...
}
पहले मैंने शत्रुओं से निपटने के लिए कुछ तरीकों के साथ हेल्पर क्लास बनाई। एक विधि को एक विशिष्ट मूल्य के लिए विवरण मिलता है, दूसरी विधि में एक प्रकार के लिए सभी मूल्य और उनके विवरण मिलते हैं।
public static class EnumHelper
{
public static string Description(this Enum value)
{
var attributes = value.GetType().GetField(value.ToString()).GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes.Any())
return (attributes.First() as DescriptionAttribute).Description;
// If no description is found, the least we can do is replace underscores with spaces
// You can add your own custom default formatting logic here
TextInfo ti = CultureInfo.CurrentCulture.TextInfo;
return ti.ToTitleCase(ti.ToLower(value.ToString().Replace("_", " ")));
}
public static IEnumerable<ValueDescription> GetAllValuesAndDescriptions(Type t)
{
if (!t.IsEnum)
throw new ArgumentException($"{nameof(t)} must be an enum type");
return Enum.GetValues(t).Cast<Enum>().Select((e) => new ValueDescription() { Value = e, Description = e.Description() }).ToList();
}
}
अगला, हम एक बनाते हैं ValueConverter। इनहेरिट MarkupExtensionकरना XAML में उपयोग करना आसान बनाता है इसलिए हमें इसे संसाधन के रूप में घोषित करने की आवश्यकता नहीं है।
[ValueConversion(typeof(Enum), typeof(IEnumerable<ValueDescription>))]
public class EnumToCollectionConverter : MarkupExtension, IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return EnumHelper.GetAllValuesAndDescriptions(value.GetType());
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
public override object ProvideValue(IServiceProvider serviceProvider)
{
return this;
}
}
मेरे ViewModelलिए केवल 1 संपत्ति की जरूरत है कि मेरे Viewदोनों के लिए करने के लिए बाध्य कर सकते हैं SelectedValueऔर ItemsSourceबता गया की:
private DayOfWeek dayOfWeek;
public DayOfWeek SelectedDay
{
get { return dayOfWeek; }
set
{
if (dayOfWeek != value)
{
dayOfWeek = value;
OnPropertyChanged(nameof(SelectedDay));
}
}
}
और अंत में बाध्य करने के लिए ComboBox(का उपयोग करते हुए देखने ValueConverterमें ItemsSourceबंधन) ...
<ComboBox ItemsSource="{Binding Path=SelectedDay, Converter={x:EnumToCollectionConverter}, Mode=OneTime}"
SelectedValuePath="Value"
DisplayMemberPath="Description"
SelectedValue="{Binding Path=SelectedDay}" />
इस समाधान को लागू करने के लिए आपको केवल मेरी EnumHelperकक्षा और EnumToCollectionConverterकक्षा की प्रतिलिपि बनाने की आवश्यकता है । वे किसी भी एनम के साथ काम करेंगे । इसके अलावा, मैंने इसे यहां शामिल नहीं किया है, लेकिन ValueDescriptionवर्ग सिर्फ 2 सार्वजनिक वस्तु गुणों के साथ एक साधारण वर्ग है, एक को बुलाया जाता है Value, एक को बुलाया जाता है Description। आप खुद बना सकते हैं या आप कोड को बदल सकते हैं Tuple<object, object>या उपयोग करने के लिएKeyValuePair<object, object>