Dapfor .Net Grid Introduction

Part1: Data Types
Part2: Data Binding
Part3: Event-driven model
Part4: Data formatting and presentation
Part5: Threadsafety
Part6: Threadsafe BindingList
Part7: Appearance and painting
Part8: Cell highlighting
Part9: Data filtering
Part10: Data sorting
Part11: Data grouping
Part12: Headers and columns
Part13: Editors
Part14: Performance. Practical recommendations
Part15: Real-time blotter
Part16: Currency converter
Part17: Instrument browser
Part18: Order book
Part19: Basket Viewer



Net Grid Tutorial Part 17: Instrument Browser

In this part of tutorial we shall demonstrate work of the grid with large data volumes on the example of Instrument browser.

The business model already contains Instrument class. We shall add only one field (quoting currency) and create a lot of instruments in the application (e.g. 100000). For this purpose we shall modify Provider class and create an arbitrary list of instruments. As before, this list will be available as follows.

 IList<Instrument> instruments = Provider.Instance.Instruments;

Now let's bind the grid to the data source. Memory consumption is one of the most important aspects of displaying large data volumes. When grid connects directly to application business logic, it significantly reduces memory consumption because there are no intermediate objects between the data layer and its presentation.

Let's create InstrumentBrowser control and place it at the main panel. We shall add a panel for instrument filtering and searching and the grid to this control. We shall configure grid in the designer and link it to the data source.

public partial class InstrumentBrowser : UserControl
{
...

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);

//Bind grid to instruments in the run-time.
if(!DesignMode)
{
grid.DataSource = Provider.Instance.Instruments;
}
}
}

The screenshot below demonstrates the results of application work.

Let's note an important detail. The collection of instruments contains about 100,000 elements. It is created when the  application is launched. Total memory consumption of the entire application is about 45 MB. This collection is bound to the grid when Instrument browser tab is opened. After that, memory consumption increases to 59 MB. This means that the grid uses about 14 MB to display 100,000 elements. This amount of elements loads for about ½ seconds.
These indicators demonstrate of grid performance with realistic numbers of instruments.

To navigate large data volumes a high performance filter is required. The grid provides a simple API for filter implementation.

//Textbox event handlers
tbIsin.TextChanged += new System.EventHandler(tbIsin_TextChanged);
private void tbIsin_TextChanged(object sender, EventArgs e)
{
_isinFilter = tbIsin.Text.ToUpper();
grid.FilterRefresh();
}

tbCurrency.TextChanged += new System.EventHandler(tbCurrency_TextChanged);
private void tbCurrency_TextChanged(object sender, EventArgs e)
{
_currencyFilter = tbCurrency.Text.ToUpper();
grid.FilterRefresh();
}

//Grid firlter implementation
grid.Filter = new Filter(OnFilterData);

//Called when data is added or each time when the business object fires PropertyChanged notification
private bool OnFilterData(Row row)
{
Instrument instrument = (Instrument) row.DataObject;
bool visible = string.IsNullOrEmpty(tbIsin.Text) || instrument.Isin.Contains(tbIsin.Text.ToUpper());
visible = visible && (string.IsNullOrEmpty(tbCurrency.Text) || instrument.Currency.Contains(tbCurrency.Text.ToUpper()));

return !visible;
}

In this application many instruments have Weight, Shares, Capitalization values equaling 0. For more convenient data interpretation it is better not to display insignificant zeroes. Besides, it is better to add thousand separators for data formatting. Use of formats is the simplest way to implement this functionality. An example of creating a simple format for displaying digital information is provided below.



public class NumericFormat : IFormat
{
public string Format(IDataField dataField)
{
return Equals(0, dataField.Value)
? string.Empty
: string.Format("{0:### ### ### ### ###}", dataField.Value);
}

public bool CanParse(string text, IDataField dataField)
{
return false;
}

public void Parse(string text, IDataField dataField)
{
}
}

public class Instrument
{
...

[Format(typeof(NumericFormat))]
public long Shares
{
get { return _shares; }
}

[Format(typeof(NumericFormat))]
public double Capitalization
{
get { return _capitalization; }
}
}

//Other way to setup a format:
Column column;
column.Format = new NumericFormat();

Now the application will look as follows.