Saya suka untuk semua objek yang saya ikat harus didefinisikan di saya ViewModel, jadi saya mencoba untuk menghindari menggunakan <ObjectDataProvider>xaml jika memungkinkan.
Solusi saya tidak menggunakan data yang ditentukan dalam Lihat dan tidak ada kode di belakang. Hanya DataBinding, ValueConverter yang dapat digunakan kembali, metode untuk mendapatkan koleksi deskripsi untuk semua jenis Enum, dan satu properti di ViewModel untuk diikat.
Ketika saya ingin mengikat sebuah Enumke ComboBoxteks saya ingin menampilkan tidak pernah cocok dengan nilai-nilai Enum, jadi saya menggunakan [Description()]atribut untuk memberikan teks yang sebenarnya ingin saya lihat di ComboBox. Jika saya memiliki enum hari dalam seminggu, itu akan terlihat seperti ini:
public enum DayOfWeek
{
// add an optional blank value for default/no selection
[Description("")]
NOT_SET = 0,
[Description("Sunday")]
SUNDAY,
[Description("Monday")]
MONDAY,
...
}
Pertama saya membuat kelas pembantu dengan beberapa metode untuk menangani enum. Satu metode mendapatkan deskripsi untuk nilai tertentu, metode lain mendapatkan semua nilai dan deskripsi mereka untuk suatu tipe.
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();
}
}
Selanjutnya, kita buat a ValueConverter. Mewarisi dari MarkupExtensionmembuatnya lebih mudah digunakan di XAML sehingga kami tidak harus mendeklarasikannya sebagai sumber daya.
[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;
}
}
ViewModelSatu-satunya kebutuhan saya adalah 1 properti yang Viewdapat saya ikat untuk keduanya SelectedValuedan ItemsSourcekotak kombo:
private DayOfWeek dayOfWeek;
public DayOfWeek SelectedDay
{
get { return dayOfWeek; }
set
{
if (dayOfWeek != value)
{
dayOfWeek = value;
OnPropertyChanged(nameof(SelectedDay));
}
}
}
Dan akhirnya untuk mengikat ComboBoxtampilan (menggunakan ValueConverterdalam ItemsSourceikatan) ...
<ComboBox ItemsSource="{Binding Path=SelectedDay, Converter={x:EnumToCollectionConverter}, Mode=OneTime}"
SelectedValuePath="Value"
DisplayMemberPath="Description"
SelectedValue="{Binding Path=SelectedDay}" />
Untuk mengimplementasikan solusi ini, Anda hanya perlu menyalin EnumHelperkelas dan EnumToCollectionConverterkelas saya. Mereka akan bekerja dengan enum apa pun . Juga, saya tidak memasukkannya di sini, tetapi ValueDescriptionkelas ini hanya kelas sederhana dengan 2 properti objek publik, satu disebut Value, satu disebut Description. Anda dapat membuatnya sendiri atau Anda dapat mengubah kode untuk menggunakan a Tuple<object, object>atauKeyValuePair<object, object>