Recently, we received an interesting feature request for showing crosshair-type overlays in FlexGrid, ComponentOne's WinForms data grid. Here's a look at how to implement crosshairs in a grid using events and styles. Before digging further into the request, let’s first look at what a crosshair is.

Crosshairs are thin vertical and horizontal lines centered on a data point, generally in a chart. When we, as UI element creators, enable crosshairs in our UI control, the end-user(s) can then hover over the UI element and be able to target/visualize a single element. You might be wondering what’s new in this requirement; after all, we've seen them in FlexChart. But this is the first we've seen a use for it in a grid.

Why use a crosshair in a WinForms grid?

Suppose we plan to show some data that gets updated on an event, such as a timer in stock market data. In such a market, stock values change every second, and it’s hard for end users to keep track of all changing values. Crosshairs help the end users by targeting them directly to the data-point/cell that just changed.

Crosshairs in a WinForms grid

How to implement crosshairs in a WinForms grid

Assuming we already have grid loaded with data getting updated on an event--Timer’s Tick for this particular example--the first action is to capture the cell whose value changed and set-up a mechanism so that we can later set styles for the row and column to which the modified cell belongs.

We plan to set styles for row and column because technically, crosshairs are nothing more than a collection of top-edge border of row and left-edge border of columns of the modified cell.

For this, we'll use FlexGrid’s CellChanged event and get the CellRange for the row, column and then set its style as follows:

//getting all cells in modified column
CellRange colRange = c1FlexGrid1.GetCellRange(1,e.Col,c1FlexGrid1.Rows.Count-1,e.Col);  
colRange.Style = c1FlexGrid1.Styles["VerticalBorder"];

//getting all cells in modified row
CellRange rowRange = c1FlexGrid1.GetCellRange(e.Row,  1, e.Row, c1FlexGrid1.Cols.Count - 1); 
rowRange.Style = c1FlexGrid1.Styles["HorizontalBorder"];

//getting the intersection cell[modifiedRow,modifiedCol]
CellStyle mergedStyle = c1FlexGrid1.Styles["MergedBorder"]; 
c1FlexGrid1.SetCellStyle(e.Row, e.Col, mergedStyle);

Now, the only remaining part is to draw the horizontal and vertical lines for showing crosshair. For this purpose, we will be using FlexGrid’s OwnerDrawCell event, and with the help of the style's name (VerticalBorder, HorizontalBorder and MergedBorder), set above, we would know which cell borders to draw. Below is the code that sets left edge borders of the column containing the cell modified:

if (style.Name == "VerticalBorder")
{
    Margins marginVr = new Margins(3, 0, 0,0);
    gr = e.Graphics;
    rec = e.Bounds;
    rec.Width = marginVr.Left;  // for drawing Vertical edge.
    gr.FillRectangle(_bdrBrush, rec);
    prevCol = e.Col;
}

Similarly, we can set the top edge borders for row.

if (style.Name == "HorizontalBorder")
{
    Margins marginHz = new Margins(0,0,3,0);
    gr = e.Graphics;
    rec = e.Bounds;
    rec.Height = marginHz.Top; // for drawing Horinzontal edge.
    gr.FillRectangle(_bdrBrush, rec);
    prevRow = e.Row;
}

Since for the modified cell, only the top and left edge borders will be the horizontal and vertical lines of the crosshair, we also need to create a combination of left-edge and top-edge borders for the cell

if (style.Name== "MergedBorder")
{
    Margins marginMrg = new Margins(3, 0, 3,0);
    gr = e.Graphics;
    rec = e.Bounds;
    rec.Height = marginMrg.Top; // for drawing Horinzontal edge.
    gr.FillRectangle(_bdrBrush, rec);

    rec = e.Bounds;
    rec.Width = marginMrg.Left;  // for drawing Vertical edge.
    gr.FillRectangle(_bdrBrush, rec);
}

Once we've completed writing the above code statements, the application is all set to display crosshairs in the grid.

Download the crosshairs sample