Make a DataGrid row read only based on a cell's value
(this page also shows how to work with delegates, events, and event
arguments)
Unfortunately .NET doesn't support this leaving you to write your own code to do
it. The C# code below shows how to disable a row based on the value of one of
its cells. Actually the row is not disabled per se. The individual cells in the
row are.
The code assumes you have a DataGrid formatted with a DataGridTableStyle.
The table style contains 2 GridColumnStyles, one
for a TextBox in column 1 and one for a data bound ComboBox in
column 2. To learn more about using data bound ComboBoxes in a grid
click here.
Column 1 contains a "Y" or "N" value. If it is "Y" the row is disabled and
cannot be edited. If it contains an "N" it can be. Changing column 1's value
from "N" to "Y" instantly disables the row.
The first step is to derive new DataGridEnableTextBoxColumn
and DataGridComboBoxColumn GridColumnStyles as
shown in the Listings 1 and 2 below. Both classes are derived from the standard
DataGridTextBoxColumn class. The Edit method
of these derived controls is overridden. Also note the EnableCellEventHandlerxxx
Delegates defined at the top these classes. You
can think of a delegate as a signature for a method.
When the Edit method is invoked it triggers the CheckxxxEnabled
event which is declared at the top of these classes. The CheckxxxEnabled
event is associated, via the delegates, with the GridColumnStyles based on the
newly derived DataGridEnableTextBoxColumn and DataGridComboBoxColumn.
The code to do this is as well as adding the custom ColumnStyles to the grid is
shown in Listing 3 below.
Listing 4 shows the SetEnableValues procedure which acts as the handler
for the CheckxxxEnabled events. This routine sets the EnableValue
flag of its DataGridEnableEventArgs parameter based on the value in
column 1 of the grid.
Finally all that's left is to define the Event Arguments
used by the EnableCellEventHandlerxxx delegates. This is done in the DataGridEnableEventArgs
class which derives from the System.EventArgs
class. This can be seen in Listing 5.
Listing 1 - The derived DataGridTextBoxColumn class:
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
namespace ReadOnly
{
public delegate void EnableCellEventHandlerTXT(
object sender, DataGridEnableEventArgs e);
public class DataGridEnableTextBoxColumn : DataGridTextBoxColumn
{
public event EnableCellEventHandlerTXT CheckTXTEnabled;
private int myColumn;
public DataGridEnableTextBoxColumn(int theColumn)
{
myColumn = theColumn;
}
protected override void Edit(
System.Windows.Forms.CurrencyManager theSource,
int theRowNum,
System.Drawing.Rectangle theBounds,
bool theReadOnlyFlag,
string theInstantText,
bool theCellIsVisibleFlag)
{
bool aEnabled = true;
if (CheckTXTEnabled != null)
{
DataGridEnableEventArgs e =
new DataGridEnableEventArgs(theRowNum, myColumn, aEnabled);
CheckTXTEnabled(this, e);
aEnabled = e.EnableValue;
}
if(aEnabled)
base.Edit(theSource, theRowNum, theBounds,
theReadOnlyFlag, theInstantText, theCellIsVisibleFlag);
}
}
}
Listing 2 - The derived DataGridTextBoxColumn class:
using System;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
namespace ReadOnly
{
public delegate void EnableCellEventHandlerCBO(
object sender, DataGridEnableEventArgs e);
public class DataGridComboBoxColumn: DataGridTextBoxColumn
{
public event EnableCellEventHandlerCBO CheckCBOEnabled;
private int myColumn;
public DataGridComboBoxColumn()
{
}
protected override void Edit(
System.Windows.Forms.CurrencyManager theSource,
int theRowNum,
System.Drawing.Rectangle theBounds,
bool theReadOnlyFlag,
string theInstantText,
bool theCellIsVisibleFlag)
{
bool aEnabled = true;
if (CheckCBOEnabled!= null)
{
DataGridEnableEventArgs e =
new DataGridEnableEventArgs(theRowNum, 0, aEnabled);
CheckCBOEnabled(this, e);
aEnabled = e.EnableValue;
}
if(aEnabled)
base.Edit(theSource, theRowNum, theBounds,
theReadOnlyFlag, theInstantText, theCellIsVisibleFlag);
}
}
}
Code Listing 3 - format the DataGrid with the derived GridColumnStyles:
// Create a aGridTableStyle to format the grid.
DataGridTableStyle aGridTableStyle = new DataGridTableStyle();
aGridTableStyle.MappingName = "myTable";
// Create GridColumnStyles basd on our derived styles.
// Here is the TextBox.
DataGridEnableTextBoxColumn aCol1 = new DataGridEnableTextBoxColumn(0);
aCol1.MappingName = "Outside_Customer";
aCol1.HeaderText = "Outside Customer";
aCol1.Width = 90;
aCol1.Alignment = HorizontalAlignment.Left;
aCol1.NullText = "N";
aCol1.TextBox.MaxLength = 1;
aCol1.TextBox.Enabled = true;
aGridTableStyle.GridColumnStyles.Add(aCol1);
// Here is the ComboBox.
DataGridComboBoxColumn aCol2 = new DataGridComboBoxColumn();
aCol2.MappingName = "Customer_ID";
aCol2.HeaderText = "Customer Name";
aCol2.Width = 90;
aCol2.ColumnComboBox.DataSource = myDataSet.Tables["myTable"].DefaultView;
aCol2.ColumnComboBox.DisplayMember = "Customer_Name";
aCol2.ColumnComboBox.ValueMember = "Customer_ID";
aCol2.NullText = "";
aGridTableStyle.PreferredRowHeight = aCol2.ColumnComboBox.Height;
aGridTableStyle.GridColumnStyles.Add(aCol2);
// Add the GridColumnStyles to the GridTableStyle.
dataGrid.TableStyles.Add(aGridTableStyle);
// Hook our new event used to disable the TextBox and ComboBox.
aCol1.CheckTXTEnabled += new EnableCellEventHandlerTXT(SetEnableValues);
aCol2.CheckCBOEnabled += new EnableCellEventHandlerCBO(SetEnableValues);
Code Listing 4 - Handler for the CheckxxxEnabled events:
private void SetEnableValues(object sender, DataGridEnableEventArgs e)
{
//
// This handler disables columns based on column 1's value.
//
string aValue = dataGrid[dataGrid.CurrentRowIndex, 0].ToString();
if (aValue == null)
aValue = "N";
if (aValue == "Y")
e.EnableValue = false;
else
e.EnableValue = true;
}
Code Listing 5 - Event arguments signature:
using System;
namespace ReadOnly
{
//
// Event argument signature used by the
// EnableCellEventHandlerxxx delegates.
//
public class DataGridEnableEventArgs : EventArgs
{
private int myColumnNumber;
private int myRowNumber;
private bool myEnableValue;
public DataGridEnableEventArgs(
int theRowNumber, int theColumnNumber, bool theValue)
{
myRowNumber = theRowNumber;
myColumnNumber = theColumnNumber;
myEnableValue = theValue;
}
public int ColumnNumber
{
get { return myColumnNumber; }
set { myColumnNumber = value; }
}
public int RowNumber
{
get{ return myRowNumber; }
set{ myRowNumber = value; }
}
public bool EnableValue
{
get{ return myEnableValue; }
set{ myEnableValue = value; }
}
}
}
|