- Download source code from here
- Please visit this project site for the latest releases and source code.
Contents
Introduction
In this article, we will focus on how to use the enum type with the Self-Tracking
Entity Generator for WPF/Silverlight. An enum is a special value type that lets
us specify a group of named numeric constants. Adding enum support is one of
the new features introduced by Entity Framework 5, which allows us to have enum properties in our entity
classes. In order to use this new feature, we need to set the target framework to .NET Framework 4.5
inside Visual Studio 2012 projects.
Adding Enum in the Entity Designer
To demonstrate how the enum type is used in WPF applications, let us go through
an example of adding a new enum type to our demo application SchoolSample. Let's say, when we create a new student record, we want to
store the information of
whether that student is a full-time or part-time student. To achieve that, we
first need to
modify our sample database and add a new field called Status
in the Person table
as follows:
CREATE TABLE [dbo].[Person](
[PersonId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
[EnrollmentDate] [datetime] NULL,
[HireDate] [datetime] NULL,
[Salary] [decimal](18, 2) NULL,
[Status] [int] NOT NULL,
[Role] [varchar](50) NOT NULL,
[Version] [timestamp] NOT NULL
)
After the sample database is updated, we open the entity designer of
SchoolModel.edmx. Right click the designer surface and choose "Update Model from Database...". After
the entity model is updated, we should be able to see a new property called Status
inside the
Person
entity as shown below.
This Status
property is initially set as Int32
type, because that
is what we have defined in the database. To change its type to enum, we need to
create a
new enum type next.
Adding a New Enum Type
To add a new enum type, we need to open the Model Browser window.
Next, look for the "Enum Types" node and right click to choose "Add New Enum
Type...".
This opens the "Add Enum Type" popup window, and we can define our new
StatusEnum
type as follows:
After adding the StatusEnum
type through the Model Browser window, we can
change the type of the Status
property in the conceptual model. From the entity designer,
select the Status
property of the Person
entity, and then from the Properties
window, change the Type dropdown and choose SCHOOLModel.StatusEnum
.
After this is done, we can now save all changes to SchoolModel.edmx.
Our next step is to re-generate entity classes on both the client (project SchoolSample.Data) and
server side (project SchoolSample.Data.Wcf). This is done by
selecting
the entity design surface, from the Properties window, choose "STE
Settings" as shown below:
After the "STE Settings" dialog box appears, click the "Update" button and it
will
generate all the newly added enum types and their helper classes:
Auto-generated Classes
The auto-generated classes include all enum types defined through the Model
Browser window and an enum helper class called EnumCollection<T>
. Following is
the StatusEnum
type we just added, and this file is generated by SchoolModel.tt:
The helper class EnumCollection<T>
is generated by SchoolModel.SteClient.tt,
and it is only available on the client side (project SchoolSample.Data).
We will discuss its main functionality next:
The EnumCollection Class
In WPF applications, we commonly use a ComboBox to bind to an enum property,
and the EnumCollection<T>
class can help us create a collection that
is used as the ItemsSource
of the ComboBox. The main features of this class are as follows:
- Creates a collection that contains every possible enum value of
T
where
each element's Value
property stores the enum value and DisplayName
property keeps its matching display name.
- Optionally, adds to the collection one element whose
Value
property stores null and DisplayName
property contains string.Empty
.
- Supports localization by retrieving the
DisplayName
property from a
resource file.
- Provides the flexibility to manually add or remove elements of the
collection.
The EnumItem Class
For the collection created by EnumCollection<T>
, its element is of
type EnumItem
. From the source code below, we can see that this class contains three properties: DisplayName
, ResourceEntryKey
, and Value
. The Value
property stores the actual
enum value, and the DisplayName
property stores its matching display name. If the ResourceEntryKey
is not empty, it contains the resource entry key where the
DisplayName
property retrieves its actual display name. The value of the ResourceEntryKey
takes the format of the enum type name, followed by an underscore and the enum value
name. For example, the ResourceEntryKey
values for StatusEnum
type are:
StatusEnum_FullTime
and StatusEnum_PartTime
.
public class EnumItem : INotifyPropertyChanged
{
public string DisplayName
{
get { return _displayName; }
set
{
_displayName = value;
OnPropertyChanged("DisplayName");
}
}
private string _displayName;
public string ResourceEntryKey { get; set; }
public T? Value
{
get { return _value; }
set
{
_value = value;
OnPropertyChanged("Value");
}
}
private T? _value;
private void OnPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
The EnumCollection Class Constructor
The constructor of class EnumCollection<T>
takes two optional parameters. The
first one is a Boolean field, if it is set to True, the collection contains a null
selection as its first element. And, the second parameter is the ResourceManager
of a resource file where the DisplayName
property retrieves its
value. If this second parameter is left as null, ResourceEntryKey
is always set as
an empty string, and the DisplayName
contains the string format of the actual enum value.
public EnumCollection(bool firstAsNull = false, ResourceManager resourceManager = null)
{
enumItems = new Collection<EnumItem>();
this.resourceManager = resourceManager;
if (firstAsNull)
enumItems.Add(new EnumItem
{
DisplayName = string.Empty,
ResourceEntryKey = string.Empty,
Value = null
});
var type = typeof (T);
foreach (var enumValue in (from field in type.GetFields(BindingFlags.Public | BindingFlags.Static)
where field.IsLiteral
select (T) field.GetValue(null)))
{
if (resourceManager != null)
{
var resourceEntryKey = string.Format("{0}_{1}", typeof (T).Name, enumValue);
var displayName = resourceManager.GetString(resourceEntryKey);
if (displayName != null)
{
enumItems.Add(new EnumItem
{
DisplayName = displayName,
ResourceEntryKey = resourceEntryKey,
Value = enumValue
});
}
else
{
enumItems.Add(new EnumItem
{
DisplayName = string.Format("{0}_{1}", typeof (T).Name, enumValue),
ResourceEntryKey = string.Empty,
Value = enumValue
});
}
}
else
{
enumItems.Add(new EnumItem
{
DisplayName = string.Format("{0}", enumValue),
ResourceEntryKey = string.Empty,
Value = enumValue
});
}
}
}
The Refresh() Method
The Refresh()
method is created to support localization and it refreshes the DisplayName
property for every item where
its matching ResourceEntryKey
is not empty. We
normally call this method after the current culture has changed.
public void Refresh()
{
if (resourceManager == null) return;
foreach (var item in enumItems.Where(n => !string.IsNullOrEmpty(n.ResourceEntryKey)))
{
var displayName = resourceManager.GetString(item.ResourceEntryKey);
if (displayName != null) item.DisplayName = displayName;
}
}
The Items Property
And finally, we expose the Items
property which returns the EnumItem
collection created by the
class constructor. This is done because we want the flexibility to add or remove any element of the EnumCollection<T>
.
public Collection<EnumItem> Items
{
get { return enumItems; }
}
This concludes our discussion of the EnumCollection<T>
class.
Next, we will see how to use this helper class in our sample ViewModel and View
classes.
Using Enum in ViewModel and View Classes
First, in class StudentPageViewModel
, we define a property
called StudentStatusCollection
of class EnumCollection<StatusEnum>
.
public EnumCollection<StatusEnum> StudentStatusCollection { get; private set; }
Next, in the class constructor, we initialize StudentStatusCollection
and pass in SchoolModelResource
as its resource file.
#region "Constructor"
[ImportingConstructor]
public StudentPageViewModel(ISchoolModel schoolModel)
{
......
StudentStatusCollection = new EnumCollection<StatusEnum>(false, SchoolModelResource.ResourceManager);
......
}
#endregion "Constructor"
Whenever the student page is loaded, we call StudentStatusCollection.Refresh()
in case there is a culture change.
private void OnPageLoadedCommand()
{
StudentStatusCollection.Refresh();
if (_schoolModel != null && _allStudentsCache != null)
_schoolModel.StudentsList = _allStudentsCache;
if (_schoolModel != null && _currentStudentCache != null)
_schoolModel.CurrentStudent = _currentStudentCache;
if (CurrentStudentHasErrors && CurrentStudent != null)
CurrentStudent.TryValidate();
}
And, after defining and initializing the StudentStatusCollection
property in the ViewModel class, we can
bind it to the ComboBox inside StudentPage.xaml as follows:
Lastly, we need to modify the SchoolModelResource.resx file with all the new DisplayName
values of the Status
enum type:
When we run the sample application, we should be able to see something similar to the following screenshot:
Wrapping Up
We have finished discussing how to use the enum type with the Self-Tracking
Entity Generator for WPF/Silverlight. First, we covered how to add a new enum
type through the Entity Designer. Then, we talked about the main functionality
of the new helper class EnumCollection<T>
. After that, we discussed how to use
the enum
in our ViewModel and View classes.
I hope you find this article useful, and please rate and/or leave feedback
below. Thank you!
History
- October, 2012 - Initial release.