When the data layer does not allow to perform calculations we often need to harness the UI.
Here is a a simple case - in our business object we have the Price and the Count properties. We will have RadGridView to calculate the Total for us in a calculated column.
If you peek into the sample project you will notice we are using a pretty standard Silverlight approach :
We bind the value of the calculated column with a Binding Converter :
<telerik:GridViewDataColumnHeader="Total"Background="Bisque"DataMemberBinding="{Binding Converter={StaticResource CalculatingConverter}}"TextAlignment="Right" />
The calculation “logic” is in the Convert method of CalculatingConverter.cs
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){return ((Item)value).Price * ((Item)value).Count;}
For simple scenarios it should do the trick . The bad thing is we have hardcoded the converter to our Item class with Price and Count properties.
What if we need a more dynamic approach - to give the RadGridView a string Expression like “Price*Count” and have it evaluate and calculate for us.
The Poor Man’s Expression Parser
A popular hack when a simple expression parser is needed in Silverlight is to call the javascript eval function from the hosting browser window.
Here is how our “dynamic expression” converter will look like :
public class CalculatingConverter : IValueConverter{public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){string stringexpression = BuildExpression(value, parameter.ToString());return HtmlPage.Window.Invoke("eval", stringexpression);}private string BuildExpression(object value, string parameter){StringBuilder sb = new StringBuilder(parameter);
foreach (PropertyInfo propertyInfo in value.GetType().GetProperties()){if (propertyInfo.CanRead)
{object o = propertyInfo.GetValue(value, null);sb.Replace(propertyInfo.Name, o.ToString());}}return sb.ToString();
}public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture){throw new NotImplementedException();}}
This gives us the power to pass the column a string expression - ‘Price*Count’ ( as a parameter of the value converter ):
DataMemberBinding="{Binding Converter={StaticResource CalculatingConverter},ConverterParameter='Price*Count'}"
For your copy/paste needs please download the
[UPDATE]
If we move the calculation logic where it belongs - the data layer, we may benefit from the INotifyPropertyChanged interface. This way the user will be able to change values in cells and get the totals recalculated in a spreadsheet alike manner. This approach is demonstrated in
.