Bağlandığım tüm nesneler için tanımlanmayı seviyorum ViewModel
, bu yüzden kullanmaktan kaçınmaya çalışıyorum<ObjectDataProvider>
mümkün olduğunca xaml .
Çözümüm, Görünüm'de tanımlanmış veri ve arkada kod kullanmıyor. Yalnızca bir DataBinding, yeniden kullanılabilir ValueConverter, herhangi bir Enum türü için açıklamaların toplanması için bir yöntem ve ViewModel'de bağlanacak tek bir özellik.
Ben görüntülemek istediğiniz Enum
bir ComboBox
metne bir bağlamak istediğinizde asla değerleri ile eşleşmez Enum
, bu yüzden [Description()]
aslında görmek istediğiniz metni vermek için özniteliği kullanın ComboBox
. Haftanın günleri bir numaralandırma olsaydı, şöyle bir şey olurdu:
public enum DayOfWeek
{
// add an optional blank value for default/no selection
[Description("")]
NOT_SET = 0,
[Description("Sunday")]
SUNDAY,
[Description("Monday")]
MONDAY,
...
}
İlk önce enums ile başa çıkmak için birkaç yöntemle yardımcı sınıf oluşturdum. Bir yöntem belirli bir değer için bir açıklama alırken, diğer yöntem bir tür için tüm değerleri ve açıklamalarını alır.
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();
}
}
Sonra bir ValueConverter
. Kaynağından devralmak XAML'de MarkupExtension
kullanımını kolaylaştırır, böylece onu bir kaynak olarak ilan etmek zorunda değiliz.
[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;
}
}
Benim ViewModel
sadece 1 özellik ihtiyacı olduğunu benim View
hem teneke bağlamak SelectedValue
ve ItemsSource
combobox:
private DayOfWeek dayOfWeek;
public DayOfWeek SelectedDay
{
get { return dayOfWeek; }
set
{
if (dayOfWeek != value)
{
dayOfWeek = value;
OnPropertyChanged(nameof(SelectedDay));
}
}
}
Ve nihayet bağlamak için ComboBox
(kullanarak görünümü ValueConverter
içinde ItemsSource
bağlanma) ...
<ComboBox ItemsSource="{Binding Path=SelectedDay, Converter={x:EnumToCollectionConverter}, Mode=OneTime}"
SelectedValuePath="Value"
DisplayMemberPath="Description"
SelectedValue="{Binding Path=SelectedDay}" />
Bu çözümü uygulamak için sadece EnumHelper
sınıfımı ve EnumToCollectionConverter
sınıfımı kopyalamanız gerekir . Herhangi bir numaralandırma ile çalışacaklar . Ayrıca, buraya dahil etmedim, ancak ValueDescription
sınıf, biri denilen Value
, biri denilen 2 ortak nesne özelliğine sahip basit bir sınıftır Description
. Bunu kendiniz oluşturabilir veya bir Tuple<object, object>
veyaKeyValuePair<object, object>