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.

BFSI

The Banking, Financial Services and Insurance industries are bundled together because they share significant characteristics, including:

  • All are highly regulated
  • They each work with large dollar amounts
  • All three typically have many offices world-wide
  • They have a large number of employees and customers
  • All interact with stocks, bonds and other financial instruments
  • They each manage their customer relationships in terms of accounts with multiple products
  • They all have a hierarchical internal structure with various levels of access to information

Examples of companies in the BFSI industries include such iconic institutions as:

  • Bank of America
  • Fidelity Investments
  • Metropolitan Life Insurance

A Common Set of Requirements

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:

  • Customer Service Representative applications for reviewing customer accounts and providing customer support
  • Broker-facing applications for managing current accounts, buying and selling stocks, examining portfolios, tracking P&L (profit & loss), etc.
  • Fund-Manager-facing applications for examining current portfolios, comparing funds, etc.
  • Analyst-facing applications for understanding the larger picture, comparing portfolios, understanding trends, and making predictions.

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.

Meeting BFSI Requirements with WPF

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 is a mature platform – critical to BFSI industries which need reliability and stability
  • WPF is close to the operating system, simplifying such tasks as data storage and retrieval and maintenance of state—particularly important where large volumes of data must be processed in real-time
  • The desktop experience is more polished—capable of meeting the expectations of today’s employees who have grown accustomed to seamless, elegant UI

WPF from a development perspective:

  • WPF uses a declarative XAML syntax making it easier to use tools such as Blend and Visual Studio
  • XAML allows simultaneous development by programmers and designers, shortening time from concept to delivery, critical in a rapidly changing environment
  • WPF lends itself to the use of the MVVM pattern making it easier to maintain and extend applications

Financial WPF Demo application

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.

Plutus Capital Investments sample WPF application

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.

Let’s Get Started

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.

The Pie Chart

PieChartTo 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>

This gives us the labeling we want, with the two values set outside the pie slice

 

The Bar Chart

WPF Bar chartLet’s turn to the bar chart. Here the process is even easier as we’ll hard code the values right into the XAML.

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

The CandleStick chart

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.

  • The opening price
  • The closing price
  • The high for the day
  • The low for the day

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.

WPF financial candlestick chart

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 ) );
         }
     }
 }

The GridView

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.

Surround the GridView with a border

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>
 

Summary

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


WPF
jesseLiberty
About the Author

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

Related Posts

Comments