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,
public
class
CapitalByGeography: INotifyPropertyChanged
{
private
double
millions;
public
double
Millions
{
get
{
return
millions; }
set
{
millions = value;
OnPropertyChanged();
}
}
private
string
area;
public
string
Area
{
get
{
return
area; }
set
{
area = value;
OnPropertyChanged();
}
}
protected
virtual
void
OnPropertyChanged( [CallerMemberName]
string
caller =
""
)
{
if
( PropertyChanged !=
null
)
{
PropertyChanged(
this
,
new
PropertyChangedEventArgs( caller ) );
}
}
public
event
PropertyChangedEventHandler 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,
public
static
ObservableCollection<CapitalByGeography> GetData()
{
var data =
new
ObservableCollection<CapitalByGeography>();
data.Add(
new
CapitalByGeography()
{ Area =
"NA"
, Millions = 43 } );
data.Add(
new
CapitalByGeography()
{ Area =
"EEMEA"
, Millions = 28 } );
data.Add(
new
CapitalByGeography()
{ Area =
"LAC"
, Millions = 15 } );
data.Add(
new
CapitalByGeography()
{ Area =
"APAC"
, Millions = 10 } );
data.Add(
new
CapitalByGeography()
{ Area =
"WE"
, Millions = 4 } );
return
data;
}
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,
class
PieLabelStrategy : ChartSeriesLabelStrategy
{
private
string
format =
"{0}\n{1:P2}"
;
public
PropertyNameDataPointBinding Binding {
get
;
set
; }
public
override
LabelStrategyOptions Options
{
get
{
return
LabelStrategyOptions.Content |
LabelStrategyOptions.DefaultVisual; }
}
public
override
FrameworkElement CreateDefaultVisual(
Telerik.Charting.DataPoint point,
int
labelIndex )
{
ChartSeries series = point.Presenter
as
ChartSeries;
return
new
TextBlock();
}
public
override
object
GetLabelContent(
Telerik.Charting.DataPoint point,
int
labelIndex )
{
if
( point ==
null
|| labelIndex < 0 )
{
return
base
.GetLabelContent( point, labelIndex );
}
return
string
.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,
public
class
StockPrice
{
public
DateTime Date {
get
;
set
; }
public
double
High {
get
;
set
; }
public
double
Low {
get
;
set
; }
public
double
Open {
get
;
set
; }
public
double
Close {
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,
public
class
StockPriceService
{
public
static
List<StockPrice> GetData()
{
var myStockPrices =
new
List<StockPrice>();
Random r =
new
Random();
DateTime date =
new
DateTime( 2013, 1, 22 );
for
(
int
i = 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 =
new
StockPrice()
{
Low = low,
High = high,
Open = open,
Close = close,
Date = date.AddMonths( i ),
};
myStockPrices.Add( stockPrice );
}
return
myStockPrices;
}
}
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,
public
class
DateTimeAxisLabelConverter : IValueConverter
{
public
object
Convert(
object
value,
Type targetType,
object
parameter,
System.Globalization.CultureInfo culture )
{
DateTime date;
if
( value
is
DateTime )
date = ( DateTime )value;
else
date = DateTime.Parse( (
string
)value );
if
( date !=
null
&& date.Month == 1 )
return
String.Format(
"{0:MMM}"
+ Environment.NewLine +
"{0:yyyy}"
, date );
else
return
String.Format(
"{0:MMM}"
, date );
}
public
object
ConvertBack(
object
value,
Type targetType,
object
parameter,
System.Globalization.CultureInfo culture )
{
throw
new
NotImplementedException();
}
}
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 property
for
our 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,
public
class
MainViewModel : INotifyPropertyChanged
{
public
ObservableCollection<CapitalByGeography> Capital {
get
;
set
; }
public
MainViewModel()
{
UpdateStockPrices();
Capital = CapitalByGeographyService.GetData();
}
public
void
UpdateStockPrices()
{
StockPrices = StockPriceService.GetData();
}
private
List<StockPrice> stockPrices;
public
List<StockPrice> StockPrices
{
get
{
return
stockPrices; }
set
{
stockPrices = value;
OnPropertyChanged();
}
}
public
event
PropertyChangedEventHandler PropertyChanged;
private
void
OnPropertyChanged(
[CallerMemberName]
string
caller =
""
)
{
if
( PropertyChanged !=
null
)
{
PropertyChanged(
this
,
new
PropertyChangedEventArgs( 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,
public
class
Company
{
public
int
ID {
get
;
set
; }
public
string
Name {
get
;
set
; }
public
int
ContributedCapital {
get
;
set
; }
public
int
TotalReturns {
get
;
set
; }
public
string
Industry {
get
;
set
; }
}
As we have before, we’ll create a CompanyService to generate the data,
public
class
CompanyService
{
public
static
ObservableCollection<Company> GetCompanies()
{
var companies =
new
ObservableCollection<Company>();
companies.Add(
new
Company() { ID = 1,
Name =
"Apollo Solar"
, ContributedCapital = 16234592,
TotalReturns = 12385375, Industry =
"Energy"
} );
companies.Add(
new
Company() { ID = 2,
Name =
"Blackstone Tech"
, ContributedCapital = 13978448,
TotalReturns = 48938263, Industry =
"Technology"
} );
companies.Add(
new
Company() { ID = 3,
Name =
"LionOre Mining Ltd"
, ContributedCapital = 44548938,
TotalReturns = 77349263, Industry =
"Mining"
} );
companies.Add(
new
Company() { ID = 4,
Name =
"Aquios Energy"
, ContributedCapital = 72397385,
TotalReturns = 100483823, Industry =
"Energy"
} );
companies.Add(
new
Company() { ID = 5,
Name =
"Brightcover Power"
, ContributedCapital = 23089777,
TotalReturns = 57394127, Industry =
"Energy"
} );
companies.Add(
new
Company() { ID = 6,
Name =
"EdiniX Technologies"
, ContributedCapital = 17556329,
TotalReturns = 21384723, Industry =
"Technology"
} );
companies.Add(
new
Company() { ID = 7,
Name =
"TerraSol"
, ContributedCapital = 81304392,
TotalReturns = 257329372, Industry =
"Mining"
} );
return
companies;
}
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:GridViewDataColumn
DataMemberBinding=
"{Binding ID}"
Header=
"ID"
/>
<telerik:GridViewDataColumn DataMemberBinding=
"{Binding Name}"
Header=
"Company"
/>
<telerik:GridViewDataColumn
DataMemberBinding=
"{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