Every developer deals with data retrieval, display and manipulation - or data binding - on a daily basis. It is one of the most common (and often one of the most boring) part of our lives. Unlike data binding in desktop environments, where all changes can be instantly reflected on a data model, Web applications require a different approach. Mono DataManager is designed to simplify data binding and transformation tasks. You can see it in action in most of the data-oriented MonoX Web parts.
Here's how you can use DataManager in your code. Data binding is configured by adding DataManagerBindings objects to the DataBindings collection. DataManagerBindings is used to define a series of data model-to-view mappings, specifying which data object properties should be bound to specific UI control properties. DataBindings collection
add method comes with a bunch of overloads that helps you to easily create bindings without the need to explicitly create DataManagerBindings object. Lets see few examples how we can configure binding
DataManager dataManager = new DataManager();
// Set binding for edit control
dataManager.DataBindings.Add(editControl, "FieldName");
// Set binding for preview and edit control
dataManager.DataBindings.Add(previewControl, editControl, "FieldName");
// Or we can set it by explicitly creating and setting DataManagerBinding object
dataManager.DataBindings.Add(new DataManagerBinding()
{
EditControl = editControl,
PreviewControl = previewControl,
PreviewControlValueProperty = "Value",
FieldName = "FieldName"
});
To define valid binding settings, only FieldName and EditControl parameters are required, all other options are optional. DataManager supports dot notation format for FieldName so you can bind control on child object properties (e.g. "Name.FamilyName"). In scenarios where you want to use a preview (read-only) mode, you can set a preview control to bind. DataManager uses
ControlValuePropertyAttribute to find which control properties to use for reading and setting values. In cases where UI control doesn't implement this attribute or you want to have different fields for getting and setting values, you can use
EditControlValueProperty to define the edit control value property or
PreviewControlValueProperty for preview control value. There are two more properties that are used for visibility management - we will discuss them later in this article.
Now when we have configured binding we can move our data easily to and from our UI via two methods,
TransferDataToControls and
TransferDataFromControls. I thing they have pretty self-explanatory names; all you need to do is to pass your data object as a parameter to these methods and DataManager will try to work its way throught their properties and transform data to appropriate fields and data types.
Of course, things are rarely so simple in the real life. More often, you will have scenarios in which you can't simply bind value to a property or you need to perform additional manual transformations, like when you have to use multiple select list. DataManager provides four events that can be used to control data transfer:
ToControlsTransfering,
ToControlTransfering,
ToControlTransfered and
ToControlsTransfered - of course, there is the same sequence of events for transfer
from controls. When you call
TransferDataToControls, first event to be fired will be
ToControlsTransfering, taking two parameters: source object and data binding configuration. This is the last place where you can adjust the binding configuration. After this, for every binding configuration,
ToControlTransfering and
ToControlTransfered will be fired with
DataManagerTransferEventArgs argument containing the source object field value, a control to bind, a control property name and its type. After binding is complete,
ToControlsTransfered is fired with the source object and a data binding configuration passed in as parameters. This is usually a good place to do all manual binding tasks.
Another handy DataManager feature is
ClearControls method. This method will reset your form on the server side by setting control value to the default type value. If you need to set some different default value or you need to reset control manually, similarly to transfer methods, ClearControls will fire chain of events where you can control form reset.
DataManager can control the visibility of dependant controls. It supports two working modes, preview and edit, via its
IsPreviewMode property. When it is set to true data will be bind to preview controls and all edit controls will be hidden. Alternatively, setting this property to false causes all edit controls to be bound, while preview controls remain unvisible. To change this behavior, you need to call
InitControlVisibility explicitly. All transfer methods and the clear method will call InitControlVisibility, so there is no need to call it manually after data transfer or form reset. Unlike various ASP .NET built-in controls like
FormView, where you have separate templates for view and edit mode (or sometimes an insert template), DataManager doesn't put any restrictions on how you define your views. Similar to the transfer events, you can control visibility initialization through four events:
VisibilityInitializing, ControlVisibilityInitializing, ControlVisibilityInitialized and
VisibilityInitialized. The parameters and working modes are just the same as for the transfer events explained earlier.
DataManager supports form validation mechanisms and takes care of synchronizing validator visibility with the current working mode. Validators are hidden when DataManager is in the preview mode, and shown in the edit mode. You can easily assign validators to UI controls at the very same time the data mapping is configured - in the Add method described above. Alternatively, you can control validators' visibility through InitControlVisibility events.
MonoX features a specialized DataManager called
DataManagerHideEmptyFields. This is an extended DataManager that will hide all the fields that aren't populated by user when preview mode is active. In most cases we are going to have rich HTML code surrounding our edit and preview controls, and it also has to be hidden is such scenarios. That's why DataManagerHideEmptyFields comes with the
ReferencedContainers collection, where you can specify all HTML code that is to be hidden when a field is not populated. You can see how to use it in the example below:
<
asp:PlaceHolder
ID
=
"Name"
runat
=
"server"
>
<
div
class
=
"field"
>
<
label
>Name</
label
>
<
asp:Label
ID
=
"NamePreview"
runat
=
"server"
/>
<
asp:TextBox
ID
=
"NameEdit"
runat
=
"server"
/>
</
div
>
</
asp:PlaceHolder
>
DataManager dataManager =
new
DataManager();
dataManager.DataBinidings.Add(
new
DataManagerBinding()
{
EditControl = NameEdit,
PreviewControl = NamePreview,
FieldName =
"FieldName"
,
ReferencedContainers =
new
Control[] { Name }
});
If
DataManagerHideEmptyFields detects that field is not populated, it will hide the complete HTML together with all server controls by hidding the referenced container - in this case PlaceHolder with the ID "Name".
I have attached a small sample page you can put inside your MonoX installation and try out DataManager in action. Happy data binding!