Programming Microsoft ASP.NET 4 - Dino Esposito [280]
Here’s the implementation of PerformDataBinding for the GaugeBar control:
protected override void PerformDataBinding(IEnumerable data)
{
// In this control, in spite of the IEnumerable type being used
// the argument "data" is a single object, not a real list to enumerate.
// You need to get an enumerator and call MoveNext once to get the effective
// content to bind.
if (data == null)
return;
var e = data.GetEnumerator();
e.MoveNext();
// Set default values for bindable properties
float displayValue = 0;
var displayText = String.Empty;
// Read the value for the Value property
if (!String.IsNullOrEmpty(DataValueField))
displayValue = (float) DataBinder.GetPropertyValue(
e.Current, DataValueField);
// Read the value for the FormatString property
if (!String.IsNullOrEmpty(DataTextField))
displayText = (String) DataBinder.GetPropertyValue(
e.Current, DataTextField);
// Fill the DataItem property
DataItem.Value = displayValue;
DataItem.Text = displayText;
}
In this particular case, the IEnumerable object passed to PerformDataBinding contains just one element. The IEnumerable interface, though, doesn’t distinguish between a single element or a list of elements. In other words, to get the data object you need to get the enumerator and move to the first item:
// data is of type IEnumerable
IEnumerator e = data.GetEnumerator();
e.MoveNext();
// Use e.Current to get the physical data object
The e.Current expression returns the data object bound to the control—that is, the container from which you extract the fields mapped to bindable properties. If you know the control is bound to, say, a DataRow object, you can retrieve the value for the Value property through the following code:
displayValue = ((DataRow) e.Current)[DataValueField];
Using the DataBinder class adds greater flexibility to your code and makes your code independent from the type of the bound data source. The GetPropertyValue method on the DataBinder class uses reflection to query the object to see whether it contains a public property with the specified name:
displayText = (string) DataBinder.GetPropertyValue(
e.Current, DataTextField);
GetPropertyValue returns an object and requires a cast to the proper type.
The remaining step is updating the rendering engine so that it accesses the DataItem object whenever it requires bound data. The BuildLabel method shown next displays the descriptive text around the gauge:
void BuildLabel(TableCell container)
{
// Calculate the value to represent
var valueToRepresent = GetValueToRepresent();
// Get the string to display on the label
var msg = GetTextToRepresent();
var lbl = new Label();
if (container is TableCell)
container.Controls.Add(lbl);
else
Controls.Add(lbl);
lbl.Text = String.Format(msg, valueToRepresent, Maximum);
}
The BuildLabel method adds a Label control to the control hierarchy under construction. The text displayed through the label is composed using the value and the format string of the gauge. Both Value and FormatString can be either data-bound or statically assigned. For this reason, you should use a get function that checks the current binding, if any, and returns the bound value or the assigned value. Note the bound value is returned in favor of an assigned value, if both are present.
float GetValueToRepresent()
{
float f = 0;
if (DataItem.Value >=0)
f = DataItem.Value;
else
f = Value;
return f;
}
string GetTextToRepresent()
{
var msg = "";
if (!String.IsNullOrEmpty(DataItem.Text))
msg = DataItem.Text;
else
msg = FormatString;
return msg;
}
No other changes are required to enhance the SimpleGaugeBar control and make it data-bound.
The following code shows the Load handler of a sample page that uses the GaugeBar control and binds it to a dynamically generated DataTable object:
public