If you want to prevent a particular ,NET
Windows Form Datagrid cell from being editable, you can
do this by deriving a custom column style and overriding its virtual Edit
member.
Expose an event as part of your derived columnstyle that
fires right before the call to the baseclass in the Edit override. This would allow the
handler of the event to set the enable value depending upon the row and column parameters
that are passed as part of the event args. The sample also fires the event right before
painting the cell to decide whether to paint a red background
for the disabled cell. You could modify the eventargs to include a backcolor, and use
this event to color cells based on row and column values.
To fully understand this example you need an understanding of the
Delegate / Event
model in C#.
- Create your own table style that will
hold your own customized column style
|
- Disable the DataGrid Cells by deriving a custom
column style and overriding its virtual Edit member.
|
- Make the DataGrid use our
own tablestyle and bind it to our table
|
Here is the complete, documented example:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlClient;
namespace DataGridDisableCell
{
// This declaration defines a delegate named
DataGridDisableCellHandler,
// which will encapsulate any method that takes two parameters:
// object: the source of the event; that is the publishing object
// DataGridDisableCellEventArgs: an object derived from
EventArgs.
public delegate void DataGridDisableCellHandler(object sender,
DataGridDisableCellEventArgs e);
// ====================== Our Application
=================================
// Disable DataGrid Cells by deriving a custom column
// style and overriding its virtual Edit member.
public class DataGridDisableCell : System.Windows.Forms.Form
{
private System.Windows.Forms.DataGrid dataGrid1;
private System.ComponentModel.Container components =
null;
public DataGridDisableCell()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components !=
null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
.....
.....
[STAThread]
public static void Main()
{
Application.Run(new
DataGridDisableCell());
}
// Create a table style that will
hold our own
// customized column style
private void DataGridDisableCell_Load(object
sender, System.EventArgs e)
{
// Fetch Table
"customers" into the DataSet
string connString = "server=xeon;" +
"uid=sa; pwd=manager;
database=northwind";
string sqlString = "SELECT * FROM
customers";
SqlDataAdapter dataAdapter = null;
DataSet _dataSet = null;
SqlConnection connection = new
SqlConnection(connString);
dataAdapter = new
SqlDataAdapter(sqlString, connection);
_dataSet = new DataSet();
dataAdapter.Fill(_dataSet,
"customers");
// Create a table
style that will hold the new column style
// that we set and also tie it to our
customer's table from our DB
DataGridTableStyle tableStyle = new
DataGridTableStyle();
tableStyle.MappingName =
"customers";
// The dataset has
things like field name and number of columns,
// we will use those to create our own
columnstyles for the columns
// in the DataGrid
int numCols =
_dataSet.Tables["customers"].Columns.Count;
DataGridTextBox dgtb; //
This is our own DataGrid Text Box
// Loop through
all DataGrid Cells and set the HeaderText, MappingName
// and enable / disable the appropriate
Cells by deriving a custom column
// style and overriding its virtual Edit
member
for (int i=0; i<numCols; ++i)
{
dgtb = new
DataGridTextBox(i);
dgtb.HeaderText =
_dataSet.Tables["customers"].Columns[i].ColumnName;
dgtb.MappingName =
_dataSet.Tables["customers"].Columns[i].ColumnName;
// ====================== Our Subscriber
=================================
// Subscribe to our
own EnableCell event handler
dgtb.DataGridDisableCell += new DataGridDisableCellHandler(SetEnableValues);
// Adds our column style to the collection
tableStyle.GridColumnStyles.Add(dgtb);
}
// Now, make the
dataGrid use our own tablestyle and bind it to our table
dataGrid1.TableStyles.Clear();
dataGrid1.TableStyles.Add(tableStyle);
dataGrid1.DataSource =
_dataSet.Tables["customers"];
}
// This is our own
DataGridDisableCell Handler. Here we can do whatever
// we want. Our Handler must conform to the paramters
defined in the delegate.
public void SetEnableValues(object sender,
DataGridDisableCellEventArgs e)
{
// OK, our sample
uses modulo 5 to disable the Cells. Note, that a Cell
// has NO disable / enable Flag, this is
done by the DataGridTextBoxColumn
// Edit Function as follows:
// Enable Cell: Call
DataGridTextBoxColumn.Edit
// Disable Cell: Do not call
DataGridTextBoxColumn.Edit
if ((e.Column + e.Row) % 2 == 0)
{
e.EnableValue = false;
// Do not call DataGridTextBoxColumn.Edit
}
else
{
e.EnableValue = true;
// Do not call DataGridTextBoxColumn.Edit
}
}
} // End of our Application:
DataGridDisableCell
// ====================== Our Publisher
=================================
// This Class is our second Paramter for our Event, it
must derived
// from EventArgs. We publish the Properties: Column, Row and
EnableValue
// to our Subscribers.
public class DataGridDisableCellEventArgs : EventArgs
{
private int _column;
private int _row;
private bool _enablevalue = true;
// Constructor, set private values
row, col.
public DataGridDisableCellEventArgs(int row, int col)
{
_row = row;
_column = col;
}
// Published Property
Column
public int Column
{
get {return _column;}
set {_column = value;}
}
// Published Property Row
public int Row
{
get {return _row;}
set {_row = value;}
}
// Published Property
EnableValue
public bool EnableValue
{
get {return _enablevalue;}
set {_enablevalue = value;}
}
}
// This is our own, customized DataGrid TextBox
Column. Here
// we draw the Cell Background and disable / enable the Cell
// according to the EnableValue in the defined Event.
public class DataGridTextBox : DataGridTextBoxColumn
{
// Declare the Event for the defined
Delegate.
public event DataGridDisableCellHandler
DataGridDisableCell;
// Save the column number
private int _col;
// Our own Constructor, which must
NOT conform the Constructor
// in the Base Class (Constructors are not
derived)
public DataGridTextBox(int column)
{
_col = column;
}
// Here is the trick for the
Background / Foreground Color
// of the Cell - override the Paint method, with our
// own functionality.
protected override void Paint(
System.Drawing.Graphics g,
System.Drawing.Rectangle bounds,
System.Windows.Forms.CurrencyManager
source,
int rowNum, // Here is the Row
Number
System.Drawing.Brush backBrush,
System.Drawing.Brush foreBrush,
bool alignToRight)
{
// Do we have
Subscribers - notify them if we have
if (DataGridDisableCell != null)
{
// Initialize our Event with the current Row and Column Number
DataGridDisableCellEventArgs e = new DataGridDisableCellEventArgs(rowNum, _col);
// Notify Subscribers to call their EventHandlers - where they
// can do whatever
they want. After this we check the EnableValue
// Flag, which may be
set / unset by a Subscriber.
DataGridDisableCell(this, e);
// Set the Foreground / Back Color according to our Subscribers
if
(!e.EnableValue)
{
backBrush = Brushes.Red;
foreBrush = Brushes.White;
}
}
// In any case
(enabled or disabled) draw the Column using the Base Method
base.Paint(g, bounds, source, rowNum,
backBrush, foreBrush, alignToRight);
}
// Here is the trick to enable / disable the TextBox
// of the Cell - override the Edit method, with our
// own functionality.
protected override void Edit(
System.Windows.Forms.CurrencyManager source,
int rowNum,
System.Drawing.Rectangle bounds,
bool readOnly,
string instantText,
bool cellIsVisible)
{
DataGridDisableCellEventArgs e =
null;
// Do we have
Subscribers - notify them if we have
if (DataGridDisableCell != null)
{
// Initialize our Event with the current Row and Column Number
e = new
DataGridDisableCellEventArgs(rowNum, _col);
// Notify Subscribers to call their EventHandlers - where they
// can do whatever
they want. After this we check the EnableValue
// Flag, which may be
set / unset by a Subscriber.
DataGridDisableCell(this, e);
}
// Only call the
Edit Method (which enables the TextBox in the DataGrid)
// when the Enable Flag has been set by
the Subscriber
if (e.EnableValue)
{
base.Edit(source,
rowNum, bounds, readOnly, instantText, cellIsVisible);
}
}
}
}