Customizing Business Rules at runtime
This series looks at the Business Logic Layer of an application from how my Peter’s Business Logic Driven UI (“BLD”) implements it. Use the “Understanding the BLL” Category to see all articles.
In the last article, you were introduced to Descriptor objects. Now you will see what I think is their most important feature: the ability to customize the business rules at runtime.
DataFieldDescriptor objects may describe a business rule and structure of a DataField, but are globally defined and must not be modified at runtime. BLD introduces the PeterBlum.DES.DataAnnotations.ActiveDataField class as a wrapper around the global DataFieldDescriptor. It exposes properties and methods that let you edit the business rules. For example, you can assign its DisplayName property to override the one in DataFieldDescriptor. If you don’t override it, DisplayName returns the localized name from the DataFieldDescriptor.
The Business Logic Layer (“BLL”) uses the PeterBlum.DES.DataAnnotations.ICustomizeDataField interface to let your BLL Entity class edit the ActiveDataField object. ICustomizeDataField adds a single method, CustomizeDataField(), which is passed the ActiveDataField object.
In the previous article, you saw how a DataFieldDescriptor for the CategoryName DataField was used to establish a disabled textbox and the text of a label. Let’s see how BLD lets you modify the IsReadOnly and DisplayName business rules of the ActiveDataField object.
[C#]
using DESDA=PeterBlum.DES.DataAnnotations;
…
public partial class Category : DESDA.ICustomizeDataField
{
public void CustomizeDataField(DESDA.ActiveDataField activeDataField)
{
switch (activeDataField.DataField)
{
case "CategoryName":
activeDataField.IsReadOnly = !CanUserEdit(); // left for you to write
activeDataField.DisplayName = GetDisplayName(); // left for you to write
break;
}
}
}
[VB]
Imports DESDA=PeterBlum.DES.DataAnnotations
…
Public Partial Class Category
Implements DESDA.ICustomizeDataField
Public Sub CustomizeDataField(activeDataField As DESDA.ActiveDataField) _
Implements DESDA.ICustomizeDataField.CustomizeDataField
Select Case activeDataField.DataField
Case "CategoryName"
activeDataField.IsReadOnly = Not CanUserEdit() ' left for you to write
activeDataField.DisplayName = GetDisplayName() ' left for you to write
Exit Select
End Select
End Sub
End Class
Your code does not edit the actual DataFieldDescriptor, but it can access it through the ActiveDataField.GlobalDataFieldDescriptor property to help build the actual business rule.
Now let’s utilize this in your UI layer. BLD boxes anything specific to a single DataField in a Field Template object. The PeterBlum.DES.BLD.BaseFieldTemplate class from which all Field Templates are created makes a fully prepared ActiveDataField available as a property. Supposing the data editing control for this Field Template is a TextBox, you might write this code:
[C#]
((TextBox)DataControl).Enabled = !ActiveDataField.IsReadOnly;
[VB]
CType(DataControl, TextBox).Enabled = Not ActiveDataField.IsReadOnly
The ActiveDataField.DisplayName property is used by the Field Template for its validator error messages, when they contain the token “{LABEL}”. If you want the customized DisplayName to appear in a Label control, use the BLDLabel control (a subclass of the Label control) and set its AssociatedControlID property to the ID of the BLDDataField control (the host control that loads the Field Template). BLDLabel will get the ActiveDataField object through the BLDDataField.
Here’s roughly what the code of the BLDLabel control looks like as it assigns its Text property.
[C#]
Control vAssociatedControl = FindControl(AssociatedControlID);
if ((vAssociatedControl != null) && (vAssociatedControl is BLDDataField))
this.Text = ((BLDDataField)vAssociatedControl).FieldTemplate.ActiveDataField.DisplayName;
[VB]
Dim vAssociatedControl As Control = FindControl(AssociatedControlID)
If (Not vAssociatedControl Is Nothing) And (vAssociatedControl is BLDDataField)) Then
Me.Text = CType(vAssociatedControl, BLDDataField).FieldTemplate.ActiveDataField.DisplayName
End If
For more on this subject, see the topics in the BLD User’s Guide.