For many developers, it’s easy to get so caught up in our day-to-day coding that we lose sight of the bigger picture. At a time when there are seemingly endless platforms from which to choose, each with its own unique offering, it is important to recognize which platform is best suited for your particular application scenario.
With that in mind, this post begins a series of articles focused on WPF development and the different industries and scenarios in which that rich, high-performance, desktop technology is used.
Today we will take a look at the Banking, Financial Services and Insurance industries.
The Banking, Financial Services and Insurance industries are bundled together because they share significant characteristics, including:
Examples of companies in the BFSI industries include such iconic institutions as:
The Banking, Financial Services and Insurance industries share a common need for back-office applications that are large and complex, and have strenuous requirements for integrity, security, and reliability. These applications often execute business intelligence analysis, manage large data-sets, and reflect complex data relationships. Many of these applications use housed data, which is often refreshed intermittently (for applications that require up-to-the-minute data many BFSI companies turn to 3rd parties like Bloomberg).
Some BFSI application scenarios you may come across are:
Another increasingly important requirement is an intuitive and beautiful User Interface. Today’s employees have grown accustomed to the elegant UI of consumer-facing applications, and a good UI is not only more pleasant to work with, it can reduce errors and save time.
There are a number of platforms that could be considered for creating the applications outlined above. However WPF is uniquely suited because it brings the ability to create information-rich applications on the desktop, which meet the security and high-performance demands described above. Because applications are information-intensive, building them is a significant challenge.
The specific characteristics of WPF that are important to the BFSI industry include:
WPF from a development perspective:
With the complexities and high demands of the BFSI industry in mind, I have built a small demo application with RadControls for WPF. No single demo application can illustrate every BFSI scenario, or all the capabilities of Telerik controls—let alone all of WPF. That said, however, I hope that my guiding you through the development of this demo application gives you some idea of how easy it is to use our controls.
The scenario we will build is for a Fund Manager who monitors the performance of a private equity fund, Plutus Capital Investments, taking note of particular trends and the distribution of assets. Information is displayed on the dashboard using RadChartView (Pie) showing the distribution of capital by geography, RadChartView (Linear) to show total fund returns over time, and RadGridView showing company name, contributed capital, total returns, and industry. Lastly, ChartView (Bar) displays the distribution of returns by industry. The goal of the dashboard is to provide information on the status of the portfolio at a glance, and access, through a drop down, to information on other funds. The demo shows only the first page of the dashboard.
The purpose of this demo is to illustrate the usage of Telerik controls, and as such we will hard code and/or randomize our data rather than focusing on the details of obtaining data from a Database or a web service. Let’s begin with the Pie chart in the upper right corner.
To create this chart, we’ll create a border and within the border we’ll add a Grid with two rows: one for the label and one for the chart. The Pie Chart itself is pretty straight forward, but our requirements call for some special label management: we want both the industry and the percentage shown and both outside the pie slices.
<Border BorderBrush="DarkGray"BorderThickness="2"Margin="5"Grid.Column="1"Grid.Row="1"><Grid><Grid.RowDefinitions><RowDefinition Height="Auto"/><RowDefinition /></Grid.RowDefinitions><TextBlock Text="Distribution of Capital by Geography"Foreground="DarkGray"/>
As always, it begins with the data. In this case, we’ll create a class named CapitalByGeography, with two public property: the number of millions of dollars, and the Area that the pie slice will cover. We can implement INotifyPropertyChanged so that as the data changes, the UI will be updated,
publicclassCapitalByGeography: INotifyPropertyChanged{privatedoublemillions;publicdoubleMillions{get{returnmillions; }set{millions = value;OnPropertyChanged();}}privatestringarea;publicstringArea{get{returnarea; }set{area = value;OnPropertyChanged();}}protectedvirtualvoidOnPropertyChanged( [CallerMemberName]stringcaller =""){if( PropertyChanged !=null){PropertyChanged(this,newPropertyChangedEventArgs( caller ) );}}publiceventPropertyChangedEventHandler PropertyChanged;}
To generate the data, and to stand in for looking up the data in a database or from a web service, we will create CapitalByGeographyService.cs. To keep things very simple, we’ll just hard code an entry for each area we are concerned with,
publicstaticObservableCollection<CapitalByGeography> GetData(){var data =newObservableCollection<CapitalByGeography>();data.Add(newCapitalByGeography(){ Area ="NA", Millions = 43 } );data.Add(newCapitalByGeography(){ Area ="EEMEA", Millions = 28 } );data.Add(newCapitalByGeography(){ Area ="LAC", Millions = 15 } );data.Add(newCapitalByGeography(){ Area ="APAC", Millions = 10 } );data.Add(newCapitalByGeography(){ Area ="WE", Millions = 4 } );returndata;}
Next, we’ll create a ViewModel class and add an Observable collection to it which we’ll initialize by calling the static method we just created,
public class MainViewModel { public ObservableCollection<CapitalByGeography> Capital { get; set; } public MainViewModel() { Capital = CapitalByGeographyService.GetData(); }Our pie chart will bind to the Capital property of the ViewModel. In MainPage.xaml.cs we’ll set the ViewModel as the data context,
public MainWindow(){ InitializeComponent(); vm = new MainViewModel(); DataContext = vm;We’re ready to create the PieChart. We’ll set its Palette to Windows 8 to get the look and feel we want for the application. The first attribute is the PieSeries whose ItemsSource is bound to the Capital collection in the VM,
<telerik:RadPieChart Palette="Windows8"Grid.Row="1"><telerik:PieSeries ItemsSource="{Binding Capital}"RadiusFactor="0.75">
Continuing on, we next set the ValueBinding which will be bound to the Millions property
<telerik:PieSeries.ValueBinding><telerik:PropertyNameDataPointBinding PropertyName="Millions"/></telerik:PieSeries.ValueBinding>
To handle the labels, however, we need to do a little special work. First, we create a PieLabelStrategy class. This derives from ChartSeriesLabelStrategy and has a public property of type PropertyNamePointBinding. In addition, we override three methods: Options, CreateDefaultVisual and GetLabelContent, as shown here,
classPieLabelStrategy : ChartSeriesLabelStrategy{privatestringformat ="{0}\n{1:P2}";publicPropertyNameDataPointBinding Binding {get;set; }publicoverrideLabelStrategyOptions Options{get{returnLabelStrategyOptions.Content |LabelStrategyOptions.DefaultVisual; }}publicoverrideFrameworkElement CreateDefaultVisual(Telerik.Charting.DataPoint point,intlabelIndex ){ChartSeries series = point.PresenterasChartSeries;returnnewTextBlock();}publicoverrideobjectGetLabelContent(Telerik.Charting.DataPoint point,intlabelIndex ){if( point ==null|| labelIndex < 0 ){returnbase.GetLabelContent( point, labelIndex );}returnstring.Format(this.format,Binding.GetValue( point.DataItem ),( ( PieDataPoint )point ).Percent / 100 );}}
We now return to the Resources section and add an entry for our strategy,
<Window.Resources><local:PieLabelStrategy x:Key="Strategy"><local:PieLabelStrategy.Binding><telerik:PropertyNameDataPointBinding PropertyName="Area"/></local:PieLabelStrategy.Binding></local:PieLabelStrategy>
With that in place, we are ready to fill in the label definition section back in the PieChart entry in the XAML,
<telerik:PieSeries.LabelDefinitions><telerik:ChartSeriesLabelDefinition Margin="-10"Strategy="{StaticResource Strategy}"/></telerik:PieSeries.LabelDefinitions>
We begin by dragging a BarChart onto the page and then adjusting the XAML that is produced. For example, rather than having two CategoricalDataPoint entries for each cluster, we’ll want three.
We start, again with a Border and a TextBlock, and then we add the chart itself. We do want the StripLines to be visible and we’ll accept the values given when we dragged the control onto the page,
<telerik:RadCartesianChart Grid.Row="1"> <telerik:RadCartesianChart.Grid> <telerik:CartesianChartGrid StripLinesVisibility="Y"> <telerik:CartesianChartGrid.YStripeBrushes> <SolidColorBrush Color="#FFD7D7D7" Opacity="0.3" /> <SolidColorBrush Color="Transparent" /> </telerik:CartesianChartGrid.YStripeBrushes> </telerik:CartesianChartGrid> </telerik:RadCartesianChart.Grid>Again, we are happy to leave the Vertical and Horizontal Axes as defined by the default grid,
<telerik:RadCartesianChart.VerticalAxis><telerik:LinearAxis /></telerik:RadCartesianChart.VerticalAxis><telerik:RadCartesianChart.HorizontalAxis><telerik:CategoricalAxis /></telerik:RadCartesianChart.HorizontalAxis>
We do have to modify the BarSeries, however, both to add a third CategoricalDataPoint to each, and to add a third Cluster. While we’re at it, we’ll change the colors of the bars,
<telerik:BarSeries CombineMode="Cluster"><telerik:BarSeries.DataPoints><telerik:CategoricalDataPoint Category="2011"Value="0.3"/><telerik:CategoricalDataPoint Category="2012"Value="0.5"/><telerik:CategoricalDataPoint Category="2013"Value="0.2"/></telerik:BarSeries.DataPoints><telerik:BarSeries.DefaultVisualStyle><Style TargetType="{x:Type Border}"><Setter Property="Background"Value="Blue"/></Style></telerik:BarSeries.DefaultVisualStyle></telerik:BarSeries><telerik:BarSeries CombineMode="Cluster"><telerik:BarSeries.DataPoints><telerik:CategoricalDataPoint Category="2011"Value="0.4"/><telerik:CategoricalDataPoint Category="2012"Value="0.2"/><telerik:CategoricalDataPoint Category="2013"Value="0.6"/></telerik:BarSeries.DataPoints><telerik:BarSeries.DefaultVisualStyle><Style TargetType="{x:Type Border}"><Setter Property="Background"Value="Green"/></Style></telerik:BarSeries.DefaultVisualStyle></telerik:BarSeries><telerik:BarSeries CombineMode="Cluster"><telerik:BarSeries.DataPoints><telerik:CategoricalDataPoint Category="2011"Value="0.2"/><telerik:CategoricalDataPoint Category="2012"Value="0.3"/><telerik:CategoricalDataPoint Category="2013"Value="0.5"/></telerik:BarSeries.DataPoints>
We can leave the DefaultVisualStyle as it was defined for us,
<telerik:BarSeries.DefaultVisualStyle><Style TargetType="{x:Type Border}"><Setter Property="Background"Value="DarkBlue"/></Style></telerik:BarSeries.DefaultVisualStyle></telerik:BarSeries></telerik:RadCartesianChart>
All in all, building this control is just a matter of knowing what to leave alone and what to change.
The Bar chart that is generated is very expressive
Our third chart is the most difficult and the most demanding, but still relatively easy to implement. Here we want to use a Candlestick chart to show four values at once for each month.
There is no good way to do this by drawing points on an X/Y grid, but the Financial Chart from Telerik overcomes this limitation by using lines and boxes. The line indicates the high and low for the month and the box indicates the open and closing prices. A solid box has a higher close, an open box has a lower close.
The red line is the trend, and we’ll get to that later in this write-up.
We start with the data. We’ll create a StockPrice class to hold all the properties we’ll need,
publicclassStockPrice{publicDateTime Date {get;set; }publicdoubleHigh {get;set; }publicdoubleLow {get;set; }publicdoubleOpen {get;set; }publicdoubleClose {get;set; }}
Notice that this class does not implement INotifyPropertyChanged. We’ll move that responsibility to the ViewModel. To generate the values, we need a service, and because we need a lot of values we’ll generate them using a random number generator,
publicclassStockPriceService{publicstaticList<StockPrice> GetData(){var myStockPrices =newList<StockPrice>();Random r =newRandom();DateTime date =newDateTime( 2013, 1, 22 );for(inti = 0; i < 36; i++ ){Double low = r.Next( i - 5, i + 5 ) * 3;Double high = low + 20;Double open = low + 10;Double close = r.Next() % 2 == 0 ? high - 5 : open - 5;var stockPrice =newStockPrice(){Low = low,High = high,Open = open,Close = close,Date = date.AddMonths( i ),};myStockPrices.Add( stockPrice );}returnmyStockPrices;}}
Again, this class stands in for obtaining these values from a database or a web service.
To create the View, we begin again with a Grid and a TextBlock to provide the label. Within the second row of the grid, we place a RadCartesianChart, and give it a name,
<telerik:RadCartesianChart Name="xStockPrices"Grid.Row="1">
The first thing to set is the HorizontalAxis, which will contain our dates. We’ll need to create a converter class to display the year for every January, so we begin by creating DateTimeAxisLabelConverter. This class implements IValueConverter and is responsible for converting the date to the string we need,
publicclassDateTimeAxisLabelConverter : IValueConverter{publicobjectConvert(objectvalue,Type targetType,objectparameter,System.Globalization.CultureInfo culture ){DateTime date;if( valueisDateTime )date = ( DateTime )value;elsedate = DateTime.Parse( (string)value );if( date !=null&& date.Month == 1 )returnString.Format("{0:MMM}"+ Environment.NewLine +"{0:yyyy}", date );elsereturnString.Format("{0:MMM}", date );}publicobjectConvertBack(objectvalue,Type targetType,objectparameter,System.Globalization.CultureInfo culture ){thrownewNotImplementedException();}}
Notice that we convert in one direction only; we leave ConvertBack unimplemented. With this class in place, we need a reference to it in our resources, and while we are at it we’ll define a DataTemplate for its use,
<local:DateTimeAxisLabelConverter x:Key="DateTimeAxisLabelConverter"/><DataTemplate x:Key="DateTimeAxisLabelTemplate"><TextBlock Text="{Binding Converter={StaticResource DateTimeAxisLabelConverter}}"TextAlignment="Center"/></DataTemplate>We can now define the HorizontalAxis propertyforour chart,<telerik:RadCartesianChart.HorizontalAxis><telerik:DateTimeContinuousAxis MajorStep="3"MajorStepUnit="Month"PlotMode="OnTicksPadded"GapLength="0.8"LabelTemplate="{StaticResource DateTimeAxisLabelTemplate}"/></telerik:RadCartesianChart.HorizontalAxis>
Notice that the MajorStepUnit is set to Month and the MajorStep is set to “3,” allowing us to write the name of every third month but still show a data point for each month.
The Vertical Axis is much simpler,
<telerik:RadCartesianChart.VerticalAxis><telerik:LinearAxis /></telerik:RadCartesianChart.VerticalAxis>
We do want the grid lines to be visible,
<telerik:RadCartesianChart.Grid><telerik:CartesianChartGrid MajorLinesVisibility="XY"/></telerik:RadCartesianChart.Grid>
We are ready to set our series. The Category will be bound to the date, an we’ll bind Open, Close, Low and High to their respective properties in the StockPrices object,
<telerik:RadCartesianChart.Series><telerik:CandlestickSeries CategoryBinding="Date"OpenBinding="Open"CloseBinding="Close"LowBinding="Low"HighBinding="High"ItemsSource="{Binding StockPrices}"/></telerik:RadCartesianChart.Series>
Finally, we’ll add a Moving Average indicator which will be computed from the StockPrices as well,
<telerik:RadCartesianChart.Indicators><telerik:MovingAverageIndicator ItemsSource="{Binding StockPrices}"ValueBinding="Close"CategoryBinding="Date"Stroke="Red"StrokeThickness="1"Period="8"/></telerik:RadCartesianChart.Indicators>
Be sure to create a StockPrices property in the MainViewModel and to set its value by calling GetData on the StockPriceService. Because we want to be able to update the prices each time the user clicks on a row in the GridView (covered next), we’ll add a public method, UpdateStockPrices. Here’s the modified View Model,
publicclassMainViewModel : INotifyPropertyChanged{publicObservableCollection<CapitalByGeography> Capital {get;set; }publicMainViewModel(){UpdateStockPrices();Capital = CapitalByGeographyService.GetData();}publicvoidUpdateStockPrices(){StockPrices = StockPriceService.GetData();}privateList<StockPrice> stockPrices;publicList<StockPrice> StockPrices{get{returnstockPrices; }set{stockPrices = value;OnPropertyChanged();}}publiceventPropertyChangedEventHandler PropertyChanged;privatevoidOnPropertyChanged([CallerMemberName]stringcaller =""){if( PropertyChanged !=null){PropertyChanged(this,newPropertyChangedEventArgs( caller ) );}}}
Finally, in the lower left corner, we’ll place a GridView. Here we don’t need a label, so we’ll just surround it with a Border, but no grid is needed.
Once again we need data to bind to; in this case we’ll create a Company class which will have all the properties we want to bind to,
publicclassCompany{publicintID {get;set; }publicstringName {get;set; }publicintContributedCapital {get;set; }publicintTotalReturns {get;set; }publicstringIndustry {get;set; }}
As we have before, we’ll create a CompanyService to generate the data,
publicclassCompanyService{publicstaticObservableCollection<Company> GetCompanies(){var companies =newObservableCollection<Company>();companies.Add(newCompany() { ID = 1,Name ="Apollo Solar", ContributedCapital = 16234592,TotalReturns = 12385375, Industry ="Energy"} );companies.Add(newCompany() { ID = 2,Name ="Blackstone Tech", ContributedCapital = 13978448,TotalReturns = 48938263, Industry ="Technology"} );companies.Add(newCompany() { ID = 3,Name ="LionOre Mining Ltd", ContributedCapital = 44548938,TotalReturns = 77349263, Industry ="Mining"} );companies.Add(newCompany() { ID = 4,Name ="Aquios Energy", ContributedCapital = 72397385,TotalReturns = 100483823, Industry ="Energy"} );companies.Add(newCompany() { ID = 5,Name ="Brightcover Power", ContributedCapital = 23089777,TotalReturns = 57394127, Industry ="Energy"} );companies.Add(newCompany() { ID = 6,Name ="EdiniX Technologies", ContributedCapital = 17556329,TotalReturns = 21384723, Industry ="Technology"} );companies.Add(newCompany() { ID = 7,Name ="TerraSol", ContributedCapital = 81304392,TotalReturns = 257329372, Industry ="Mining"} );returncompanies;}
We could just bind, but we want to control the appearance of each column header, so we’ll turn off AutoGenerateColumns and we’ll generate the columns and their binding by hand. Here’s the complete RadGridView.
<telerik:RadGridView Name="xGridView"AutoGenerateColumns="False"><telerik:RadGridView.Columns><telerik:GridViewDataColumnDataMemberBinding="{Binding ID}"Header="ID"/><telerik:GridViewDataColumn DataMemberBinding="{Binding Name}"Header="Company"/><telerik:GridViewDataColumnDataMemberBinding="{Binding ContributedCapital}"Header="Contributed Capital"/><telerik:GridViewDataColumn DataMemberBinding="{Binding TotalReturns}"Header="Total Returns"/><telerik:GridViewDataColumn DataMemberBinding="{Binding Industry}"Header="Industry"/></telerik:RadGridView.Columns></telerik:RadGridView>
We’ve seen that the Banking, Financial Services and Insurance industries have very demanding requirements that can best be met by information-rich WPF applications. We’ve also seen how Telerik WPF controls can help you rapidly develop the applications that manage that information.
Do you work in the BFSI industry? What scenarios do you encounter? What strengths and weaknesses do you find in using WPF? If you’re not in the BFSI industry, do you see similar challenges in your industry? How do they differ?
Next up: Manufacturing. Stay tuned to Michael Crump’s Telerik blog!
Download the source code for this example here
Jesse Liberty has three decades of experience writing and delivering software projects. He is the author of 2 dozen books and has been a Distinguished Software Engineer for AT&T and a VP for Information Services for Citibank and a Software Architect for PBS. You can read more on his personal blog or follow him on twitter