Introduction
I was sitting around trying to recall WPF-related programming problems I had over the years, and remembered one involving creating observable collections of enumerator values. This happened to me long ago, and I can't find the code where I resolved the issue, but I do remember that it was specific to the enumerator involved, and that's actually a "bad thing" (TM). This article presents a debuggable generic approach, and should work for any enumerator you might decide is important. I won't pretend that this is the only or best way to approach the problem, but I can guarantee that it will work, and is certainly viable (in my eyes, at least). That being said, there are a couple of all-XAML solutions to the issue (and a simple Google search will reveal those methods), but I like the MVVM way of doing things and the debugging capabilities that provides.
This article will admittedly be pretty short, and it will have no screen shots or accompanying downloadable file because all of the source will be presented in a single <pre> block, and will be easily copy/pasteable into your own project.
UIdate! (2021.02.23) - I posted this article which exercises the concept presented here - WPF - Dedicated Enumerator ListBox and ComboBox[^]
The Problem, and the Solution
In WPF, collections should be observable in order to work well with the UI, but enumerators aren't coducive to being in this manner. My solution is to write an extension method, and a free-standing static method that presents a given enumerator as an ObservableCollection
. Without further ado (fuss, work, or delay, as opposed to the C# ADO framework), here's the code:
using System;
using System.Collections.ObjectModel;
namespace ObjectExtensions
{
public class EnumItem
{
public object Value { get; set; }
public string Name { get; set; }
public Type EnumType { get; set; }
public Type UnderlyingType { get; set; }
}
public static class ExtendEnum
{
public static ObservableCollection<EnumItem> AsObservableEnum(this Enum enumObj)
{
Type enumType = enumObj.GetType();
return AsObservableEnum(enumType);
}
public static ObservableCollection<EnumItem>AsObservableEnum(Type enumType)
{
ObservableCollection<EnumItem> list = null;
if (enumType != null && enumType.IsEnum)
{
Type underlyingType = Enum.GetUnderlyingType(enumType);
list = new ObservableCollection<EnumItem>();
foreach (Enum item in enumType.GetEnumValues())
{
list.Add(new EnumItem()
{
Name = item.ToString(),
Value = item,
EnumType = enumType,
UnderlyingType = underlyingType
});
}
}
return list;
}
}
}
Using the code
Usage is typical in your standard WPF application. Since enumerators don't change their contents beyond their actual definition, it would be a good idea to somehow create the resulting observable enum collection as a static object (contained in a global static class or as a singleton object, or even a combination of both). Creating it once as a static object means you won't be spending time re-allocating the object over and over, which will prevent heap fragmentation and ultimately save CPU cycles. For simple testing, though, you can do the following in your window's code-behind:
public class MainWindow : Window, INotifyPropertyChanged
{
private ObservableCollection<EnumItem> enums;
public ObservableCollection<EnumItem> Enums
{
get { return this.enums; }
set { if (value != this.enums) { this.enums = value; this.NotifyPropertyChanged(); } }
}
public MainWindow()
{
this.InitializeComponent();
this.DataContext = this;
this.Enums = DayOfWeek.Monday.AsObservableEnum();
}
}
And in your XAML, you might want to use a ListBox to allow selection of the presented enumerator:
<ListBox ItemsSource="{Binding Path=Enums}" Height="120" Width="120" DisplayMemberPath="Name"/>
Once an enum value has been selected in your UI, you have complete access to the parent enum type for whatever purpose you might come up with.
Points of Interest
I maintain an assembly that contains nothing but extension methods, and this technique has been added to it. Each data type gets its own file, so for instance, I have classes/files called ExtendXMLToLinq
, ExtendString
, ExtendIEnumerable
, etc. I recommend that if you do a lot of c# coding, that you start your own assembly. Believe me, your coding life will be easier if you start doing this now.
History
- 2021.02.22 - Initial publication.
I've been paid as a programmer since 1982 with experience in Pascal, and C++ (both self-taught), and began writing Windows programs in 1991 using Visual C++ and MFC. In the 2nd half of 2007, I started writing C# Windows Forms and ASP.Net applications, and have since done WPF, Silverlight, WCF, web services, and Windows services.
My weakest point is that my moments of clarity are too brief to hold a meaningful conversation that requires more than 30 seconds to complete. Thankfully, grunts of agreement are all that is required to conduct most discussions without committing to any particular belief system.