Silverlight 3 Data Editing abilities


I’ve been looking at Silverlight 3 (SL3) lately and seen some of the data editing features of it – really, really impressed with it. SL3 comes with lots of great-looking controls such as: –

  • Charting
  • Calendar, Date and Time Pickers
  • Tab Control
  • Auto Complete boxes

It’s actually getting to the stage where Silverlight is in some ways appearing to be a more compelling choice than WPF as a way to write rich UIs, since the control set has become that much richer. Anyway, the two controls that I was most interested in were the Data Form and the Data Grid controls – two controls that for any LOB and data capture you’ll want to be using…

Data Form

This is a generic control to edit the fields of a particular entity. It supports change tracking, paging / record navigation, validation, and tooltips. Here is a simple Employee entity:

public class Employee
{
public string Name { get; set; }
public string Project { get; set; }
public string Skillset { get; set; }
}

Basic Functionality

To edit this entity in the Data Form, drag on a DataForm and set the ItemSource property in code: –

Here’s the (slightly simplified) XAML. I’ve just removed some of the initialisation XAML but the Grid area is the bit we are interested in and it’s completely unchanged.

<UserControl
xmlns:dataFormToolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm.Toolkit"
x:Class="SilverlightApplication1.MainPage"
Loaded="UserControl_Loaded"
Background="AliceBlue">
<Grid>
<dataFormToolkit:DataForm Name="dataForm"/>
</Grid>
</UserControl>

And here’s the code for the UserControl_Loaded event. I’m creating some “fake” employees and then binding that to the grid.

private void UserControl_Loaded (object sender, RoutedEventArgs e)
{
employees = new List<Employee>
{
new Employee { Name = "Isaac", Skillset = ".NET", Project = "TCP" },
new Employee { Name = "Tim", Skillset = "Business Analysis", Project = "Client 1" },
new Employee { Name = "Fred", Skillset = "XRM", Project = "Client 3" },
new Employee { Name = "Jane", Skillset = "SQL", Project = "Client 2" }
};

this.dataForm.ItemsSource = employees;
}

Here’s what we get when we run our app:

image We can now edit any of the properties and the control has automatically bound them to the underlying datasource. Notice also the record browser at the top right of the form. By clicking the + button, the control will automatically create a new entity and add it to the ItemSource; similarly hitting the – button will remove the entity.

image Here I’ve hit the “+” button to create a new entity. Pressing OK pushes the new entity into the collection, Cancel drops it. Also remember that this form is being dynamically generating based on the entity’s public properties.

Further functionality

The data form control can also do much more than basic editing of data. By decorating our entity with certain attributes, the control will do: –

  • Validation
  • Tooltips
  • Field Description

Here’s a revised version of the Employee entity: –

public class Employee
{
[Display (Name = "Employee's full name", Description = "The name of the employee", Prompt = "Enter the user's name here...")]
[Required (ErrorMessage = "You must enter a name for this employee")]
public string Name { get; set; }
[StringLength (16, MinimumLength=3, ErrorMessage = "Project name must be between 5 and 16 characters long")]
public string Project { get; set; }
[ReadOnly(true)]
public string Skillset { get; set; }
}

I’ve now put a few attributes on some of the fields; by now re-running my code, without any change to the data form, I get this:

image

Notice that: –

  • The first field now takes the “Name” parameter on the Display attribute
  • The first field is shown in bold to indicate that it is Required.
  • The third field has a grey background to indicate that it is read-only.
  • The first field has an “i” icon next to it. Hovering over it displays a tooltip:

image

If you fail the validation on any of the fields, when trying to leave that record you get the following:

image

Clicking on any of the errors sets the cursor focus to the field in question. I am pretty sure that you can control the styling of all of this through XAML, but the default look and feel seems pretty OK to me. This validation will also kick in automatically if you e.g. enter a string into a integer field.

More control over editing

You can also set a few properties on the control to specify whether editing and committing of changes happens implicitly (as above) or explictly (see below). When you are explicitly editing data, you first have to the hit the “Edit” button in the record navigator to edit the record in view; then you hit the OK button (which only appears in Edit mode) to persist your changes.

image

image

Change Tracking

You’ll notice in the last screenshot that there is no Cancel button. That’s because your entity does not track what it’s been changed to. But you can fix this by implementing IEditableObject on your entity; I’ve done it on my Employee class below:

public class Employee : IEditableObject
{
[Display (Name = "Employee's full name", Description = "The name of the employee", Prompt = "Enter the user's name here...")]
[Required (ErrorMessage = "You must enter a name for this employee")]
public string Name { get; set; }
[StringLength (16, MinimumLength=3, ErrorMessage = "Project name must be between 5 and 16 characters long")]
public string Project { get; set; }
[ReadOnly(true)]
public string Skillset { get; set; }

#region IEditableObject
private Employee originalValue;

/// <summary>
/// Causes the object to enter editing mode.
/// </summary>
public void BeginEdit ()
{
originalValue = new Employee { Name = this.Name, Project = this.Project, Skillset = this.Skillset };
}

/// <summary>
/// Causes the object to leave editing mode and revert to the previous, unedited value.
/// </summary>
public void CancelEdit ()
{
this.Name = originalValue.Name;
this.Project = originalValue.Project;
this.Skillset = originalValue.Skillset;
}

/// <summary>
/// Causes the object to leave editing mode and commit the edited value.
/// </summary>
public void EndEdit ()
{
originalValue = null;
}
#endregion
}

 

All I’m doing in the above code is making a copy of the object as soon as you BeginEdit. If CancelEdit is called, I revert back to the old version of the entity, otherwise if EndEdit is called I remove the backup copy. Now when we edit any entities we get a Cancel button, too! This obviously calls CancelEdit above, whereas OK calls EndEdit.

image

DataForm looks like it’s a very powerful control that will save us lots of time when editing basic data on an entity. Because it has inbuilt support for validation (with support for RegEx as well) and change tracking, it’s something that could be of real use with LOB applications.