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 Enum
ke ComboBox
teks 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 MarkupExtension
membuatnya 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;
}
}
ViewModel
Satu-satunya kebutuhan saya adalah 1 properti yang View
dapat saya ikat untuk keduanya SelectedValue
dan ItemsSource
kotak kombo:
private DayOfWeek dayOfWeek;
public DayOfWeek SelectedDay
{
get { return dayOfWeek; }
set
{
if (dayOfWeek != value)
{
dayOfWeek = value;
OnPropertyChanged(nameof(SelectedDay));
}
}
}
Dan akhirnya untuk mengikat ComboBox
tampilan (menggunakan ValueConverter
dalam ItemsSource
ikatan) ...
<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 EnumHelper
kelas dan EnumToCollectionConverter
kelas saya. Mereka akan bekerja dengan enum apa pun . Juga, saya tidak memasukkannya di sini, tetapi ValueDescription
kelas 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>