Friday, April 29, 2011

Create CRUD UI using ASP.NET 4.0, FormView, Dynamic Data, DomainDataSource, Entity Framework, WCF Domain Service, LINQ, and custom validation – Part II

This is one entry in a series of blog entries:

Adding Labels based on MetaData from Model

In Part I we did some pretty neat stuff with Dynamic Data. In this blog entry I will show how to have your labels be set to what is set in the MetaData.

Let’s do some additional clean up here. Let’s remove the ProductCategoryID and ProductModelID fields since they will never be used.

Next we need to replace static text labels with a Label control so that we can set it via code. For example, replace ProductID with

<asp:Label ID="lblProductID" runat="server" AssociatedControlID="ProductIDDynamicControl"  OnLoad="LoadLabelForDynamicControl"></asp:Label>

I recommend a consistent naming convention to make remembering control ids. Once you have replaced one template such as the EditItemTemplate you can copy it to the InsertItemTemplate and the ItemTemplate, but be sure to change the Mode property to Insert and ReadOnly respectively.

Since we will have to get the metadata for each column on the FromView we will create a method that does this for us. Below is that method.

/// <summary>
/// Assuming you have a Label and DynamicControl (with the AssoicatedControlID on the label control set to the DynamicControl)
/// on your FormView it will set the text of the label control to the DisplayName which is from the MetaColumn for the column
/// used by the DynamicControl.
/// </summary>
/// <param name="labelControl">The label control that will have its text changed</param>
private void SetLabelBasedOnMetaData(Label labelControl)
    string dynamicControlID = labelControl.AssociatedControlID;
    if (string.IsNullOrEmpty(dynamicControlID)) throw new Exception("The AssociatedControlID must be set for Label control with ID: " + labelControl.ID);

    var container = labelControl.NamingContainer;
    var userControl = container.FindControl(dynamicControlID) as DynamicControl;
    if (userControl == null) throw new Exception("Could not find dynamic control with id: " + dynamicControlID);

    labelControl.Text = userControl.Column.DisplayName;

This will be called from the OnLoad event for each label.

protected void LoadLabelForDynamicControl(object sender, EventArgs e)
    Label labelControl = sender as Label;

If you run this now you will see that there is no real difference from the user’s perspective. However, the labels are being pulled from the MetaData (the Model). Now we just need to specify the label we want to display. This is the same label that is used in generated error messages.


To specify the labels, open the AWDomainService.metadata.cs and find the property you want to set the label for and add the following line.

[Display(Name="Product ID")]
public int ProductID { get; set; }

Do this for each property. Re-run and this time you will see that the labels are the values you set in the Display attribute.

It is a little more work, but in the end your labels will always be in sync from screen to screen and your error messages will reflect the name as well. When you need to make a change, you just do it once in your model. It is also the same information that your scaffolded screens will use as well.


All source for this project can be downloaded here.

No comments: