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.

 

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:GridViewDataColumn 
 Header="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

 

 

.


Related Posts

Comments