Skip to main content Skip to footer

How to Disable Focus for Columns in C1FlexGrid

ComponentOne provides two grid components: C1FlexGrid and C1TrueDBGrid. While both are robust, easy-to-use grid controls that allow you to browse, edit, add, delete, and manipulate tabular data, there are several features that differentiate one another. Though it is not possible to incorporate all the features of TrueDBGrid in FlexGrid and vice-versa as both of them have their own object models that apply to the different business scenerios. One such feature is the ability of a column to receive focus in C1TrueDBGrid. However, this feature is not directly available in C1FlexGrid but, it can be achieved very easily by using some of the events and properties provided in C1FlexGrid. The following is a step by step walkthrough to add this feature to your applications. Please note, for the sake of understanding we will call this feature as AllowFocus, and its meaning remains the same throughout this blog (unless stated otherwise).

The Implementation

Step 1 - Initialize collections which would store the AllowFocus feature for all the columns

A collection FocusCols of Boolean variables is created. The index value of each variable corresponds to the column index (normalized to fixed and frozen columns):

List FocusCols = new List();  
foreach (Column col in c1FlexGrid1.Cols)  
{  
    if (col.Index >= (c1FlexGrid1.Cols.Fixed + c1FlexGrid1.Cols.Frozen))  
    {  
        FocusCols.Add(false);  
    }  
}

A collection FocusColsCheck of Checkboxes is created. The index value of each checkbox in this collection corresponds to the variables in FocusCols collection. Changing the checked state of these checkboxes will change the value in FocusCols. These checkboxes are used for presentation purposes only:

List FocusColsCheck = new List();  
foreach (Column col in c1FlexGrid1.Cols)  
{  
    if (col.Index >= (c1FlexGrid1.Cols.Fixed + c1FlexGrid1.Cols.Frozen))  
    {  
        CheckBox chk = new CheckBox();  
        // set the checkbox properties  
        chk.CheckedChanged += new EventHandler(chk_CheckedChanged);  
        this.c1FlexGrid1.Controls.Add(chk);  
        FocusColsCheck.Add(chk);  
    }  
}

Checkboxes are placed on the column header for the specific column. Please note that we are not implementing the AllowFocus feature on fixed and frozen columns. If you wish to do otherwise, you can change the necessary code. For presentation purposes, the checkboxes are visible only when the AllowFocus for the specific column is set to false, or when the mouse pointer is over column header:

void chk_CheckedChanged(object sender, EventArgs e)  
{  
    CheckBox chk = (CheckBox)sender;  
    if (chk.Checked == true)  
        chk.Visible = true;  
    else  
        chk.Visible = false;  
    FocusCols[Convert.ToInt32(chk.Tag.ToString())] =Convert.ToBoolean(chk.Checked.ToString());  
    this.c1FlexGrid1.Focus();  
    this.c1FlexGrid1.BeforeRowColChange += new RangeEventHandler(c1FlexGrid1_BeforeRowColChange);  
    if (this.c1FlexGrid1.Selection.c1 == Convert.ToInt32(chk.Tag.ToString()) + 1)  
    {  
        bool flagger = false;  
        foreach (bool b in _lbFocusCols)  
        {  
            if (b == false)  
                flagger = true;  
        }  
        if (flagger == true)  
        {  
            bool rightFlag = false;  
            bool leftFlag = false;  
            for (int i = Convert.ToInt32(chk.Tag.ToString()); i < _lbFocusCols.Count; i++)  
            {  
                if (_lbFocusCols[i] == false)  
                    rightFlag = true;  
            }  
            if (rightFlag)  
            {  
                while ((\_lbFocusCols[this.c1FlexGrid1.Selection.c1 - 1]) && (this.c1FlexGrid1.Selection.c1 < this.c1FlexGrid1.Cols.Count - 1))
                 {
                     try
                     {
                         this.c1FlexGrid1.Select(this.c1FlexGrid1.Selection.r1, this.c1FlexGrid1.Selection.c1 + 1);                     
                     }
                     catch
                     {
                     }
                 }
             }
             else
             {
                 leftFlag = true;
             }
             if (leftFlag || (this.c1FlexGrid1.Selection.c1 == this.c1FlexGrid1.Cols.Count - 1 && \_lbFocusCols[this.c1FlexGrid1.Selection.c1 - 1]))
             {
                 bool flag = false;
                 int col = 0, c = 0;
                 foreach (bool b in _lbFocusCols)
                 { 
                    c++; 
                    if (b == false)
                     {
                         flag = true;
                         col = c;
                     }
                 } 
                if (flag == true)
                 {
                     this.c1FlexGrid1.Select(this.c1FlexGrid1.Selection.r1, col);
                 }
                 else
                 {
                     this.c1FlexGrid1.FinishEditing();
                 }
             }
         }
         else
         {
             this.c1FlexGrid1.FinishEditing();
         }
     }
 }

These checkboxes are placed on the FlexGrid column headers:

void c1FlexGrid1_Paint(object sender, PaintEventArgs e) {     int index = 0;     foreach (C1.Win.C1FlexGrid.Column col in c1FlexGrid1.Cols)     {          if (col.Index >= (c1FlexGrid1.Cols.Fixed + c1FlexGrid1.Cols.Frozen))  
         {  
             FocusColsCheck[index].Location = new Point(c1FlexGrid1.GetCellRect(0, col.Index).Right - 3 * FocusColsCheck[index].Width, c1FlexGrid1.GetCellRect(0, col.Index).Bottom - FocusColsCheck[index].Height - 5);  
             index++;  
         }  
    }  
}

Step 2 - Implement the focus logic in two events

When the AllowFocus for the particular column is set to false, cells in those columns must not get focus. To implement this we need to cancel the events causing focus in those cells. This is done by manipulating the BeforeMouseDown and BeforeRowColChange events. BeforeMouseDown Only the header of the column should be clickable in a column:

void c1FlexGrid1_BeforeMouseDown(object sender, BeforeMouseDownEventArgs e)  
{  
    C1.Win.C1FlexGrid.HitTestInfo hit = c1FlexGrid1.HitTest(e.X, e.Y);  
    if (hit.Type == HitTestTypeEnum.Cell)  
    {  
        if (FocusCols[(hit.Column - (c1FlexGrid1.Cols.Fixed + c1FlexGrid1.Cols.Frozen))])  
        {  
            if (hit.Row != 0)  
                e.Cancel = true;  
        }  
    }  
}

BeforeRowColChange When the cell focus is changed using keyboard, the column with AllowFocus set to false must be skipped. This feature is observed in TrueDBGrid:

void c1FlexGrid1_BeforeRowColChange(object sender, RangeEventArgs e)  
{  
    if (e.NewRange.IsSingleCell)  
    {  
        int NewColumn = e.NewRange.c1;  
        int OldColumn = e.OldRange.c1;  
        if (OldColumn != NewColumn)  
        {  
            if (FocusCols[NewColumn - (c1FlexGrid1.Cols.Fixed + c1FlexGrid1.Cols.Frozen)])  
            {  
                e.Cancel = true;  
                c1FlexGrid1.Select(e.NewRange.r1, FindNextUnlockedCol(OldColumn, NewColumn));  
            }  
        }  
    }  
    int FindNextUnlockedCol(int OldColumn, int NewColumn)  
    {  
        if (OldColumn < NewColumn)  
        {  
            while (FocusCols[NewColumn - (c1FlexGrid1.Cols.Fixed + c1FlexGrid1.Cols.Frozen)])  
            {  
                NewColumn++;  
                if (NewColumn == c1FlexGrid1.Cols.Count)  
                    return OldColumn;  
            }  
            return NewColumn;  
        }  
        else  
        {  
            while (FocusCols[NewColumn - (c1FlexGrid1.Cols.Fixed + c1FlexGrid1.Cols.Frozen)])  
            {  
                NewColumn--;  
                if (NewColumn == (c1FlexGrid1.Cols.Fixed + c1FlexGrid1.Cols.Frozen - 1))  
                    return OldColumn;  
            }  
            return NewColumn;  
        }  
}

This ends the implementation of AllowFocus for columns in FlexGrid.

Step 3 - Molding through rough edges

There are still some issues in the above implementation.

  • What if the rows are dragged? In this case, the checkbox's position must also change.

    void c1FlexGrid1_AfterDragColumn(object sender, DragRowColEventArgs e)  
    {  
        int NewPosition = e.Position - (c1FlexGrid1.Cols.Fixed + c1FlexGrid1.Cols.Frozen);  
        int OldPosition = e.Col - (c1FlexGrid1.Cols.Fixed + c1FlexGrid1.Cols.Frozen);  
        bool temp = FocusColsCheck[NewPosition].Checked;  
        FocusColsCheck[NewPosition].Checked = FocusColsCheck[OldPosition].Checked;  
        FocusColsCheck[OldPosition].Checked = temp;  
        FocusCols[NewPosition] = FocusColsCheck[NewPosition].Checked;  
        FocusCols[OldPosition] = FocusColsCheck[OldPosition].Checked;  
        c1FlexGrid1.Refresh();  
    }
    
  • The check-boxes must be visible while the mouse is on the column header, and should be invisible for rest of the time.
    void c1FlexGrid1_MouseMove(object sender, MouseEventArgs e)  
    {  
        C1.Win.C1FlexGrid.HitTestInfo hit = c1FlexGrid1.HitTest(e.X, e.Y);  
        int i = 0;  
        if (hit.Type == HitTestTypeEnum.ColumnHeader)  
        {  
            foreach (CheckBox chk in FocusColsCheck)  
            {  
                if (chk.Checked == true)chk.Visible = true;  
                    if (chk.Checked == false)  
                        if (i == (hit.Column - this.c1FlexGrid1.Cols.Fixed - this.c1FlexGrid1.Cols.Frozen))  
                            chk.Visible = true;  
                        else  
                            chk.Visible = false;  
                        i++;  
            }  
        }  
        else  
        {  
            foreach (CheckBox chk in FocusColsCheck)  
            {  
                if (chk.Checked == true)  
                    chk.Visible = true;  
                else  
                    chk.Visible = false;  
            }  
        }  
    }
    
  • There must be a programmatic way to get and set focus for the column.
    private bool GetFocus(int index)  
    {  
        return FocusCols[index - this.c1FlexGrid1.Cols.Fixed - this.c1FlexGrid1.Cols.Frozen];  
    }  
    
    private void SetFocus(int index)  
    {  
        this.FocusColsCheck[index - this.c1FlexGrid1.Cols.Fixed - this.c1FlexGrid1.Cols.Frozen].Checked = true;  
    }
    

A .gif showing column checkbox filtering within FlexGrid

Thus, we get a completely new feature in C1FlexGrid.

Hunter Haaf