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);
}
}
}
}