// note: on the very first time this routine is called you MUST set the column as visible
// ahead of setting a position in the items collection. otherwise the combobox will not be
// populated and the call to set the SelectedValue cannot succeed
//if there is no this value in this combobox,Don't display the combobox
DataRow[] aRowA;
aRowA=((DataTable)_objSource).Select(_strValue + " = " + anObj);
if(aRowA.Length>0)
{
_cboColumn.Visible = true;
}
// use the object to set the combobox. the null detection is primarily aimed at the addition of a
// new row (where it is possible a default column-row content has not been defined)
if (anObj.GetType() != typeof(System.DBNull))
{
_cboColumn.SelectedValue = anObj;
}
else
{
_cboColumn.SelectedIndex = 0;
}
// we've set the combobox so we can now paint the control and move focus onto it
_cboColumn.EndUpdate();
_cboColumn.Focus();
// below is the default method which we definitely DONT want to call as the text box must remain dormant!
// base.Edit(source, rowNum, bounds, readOnly, instantText, cellIsVisible);
//做呈现用,禁止编辑
_cboColumn.Visible=false;
}
public void cboColumn_Leave(object sender, EventArgs e)
{
// We are going to write back the ValueMember from combobox into the current column-row in the
// table displayed by the DataGrid control. Finally we hide the combobox. note the source and
// row were saved when the edit began - see Edit()
object objValue = _cboColumn.SelectedValue;
// we can write System.DBNull back to a database but we cannot write null (which would
// cause an exception). if the combobox is defined as a dropdownlist we cannot see the
// null value. However if the combobox is defined as a dropdown then editing into the
// combobox will, by default, generate a null value. For this possibility we translate
// null to the System.DBNull value
// this method is called to draw the box without a highlight (ie when the cell is in unselected state)
protected override void Paint(Graphics g, Rectangle bounds, CurrencyManager source, int rowNum, Brush backBrush, Brush foreBrush, bool alignToRight)
{
// there are three Paint() methods that can be overriden. I put break points in all three, but this
// was the only one I caught. If you find odd paint behaviors please let me know and I'll investigate
string strCountry;
DataRow[] aRowA;
// retrieve the value at the current column-row within the source for this column
object anObj = this.GetColumnValueAtRow(source, rowNum);
// use this value to access the datasource. again, we must allow that a null object
// is returned; this typically only happens when adding a new row to the DataGrid host
Type aType = anObj.GetType();
if (aType != typeof(System.DBNull))
{
if(aType==typeof(System.String))
{
aRowA = ((DataTable)_objSource).Select(_strValue + "='" + anObj+"'");
}
else
{
aRowA = ((DataTable)_objSource).Select(_strValue + "=" + anObj);
}
if(aRowA.Length<=0)
{
strCountry="-无-";
}
else
{
strCountry = aRowA[0][_strMember].ToString();
}
}
else
{
strCountry=this.NullText;
}
//if (aRowA.Length > 0)
//{
// strCountry = aRowA[0][_strMember].ToString();
//}
// all we are going to do is repaint the cell. Empiric observation indicates this code is ONLY
// called when the column is not in edit mode, however you could wrap conditional code around
// this to block an unwanted paint event calling during an edit operation
Rectangle rect = bounds;
// use custom background color if the property was set by the User
if (this._backBrush == null)
g.FillRectangle(backBrush, rect);
else
g.FillRectangle(_backBrush, rect);
// vertical offset to account for frame of combobox
rect.Y += 2;
if (this._foreBrush == null)
g.DrawString(strCountry, this.TextBox.Font, foreBrush, rect);
else
g.DrawString(strCountry, this.TextBox.Font, _foreBrush, rect);
}
public System.Drawing.Color backgroundColour
{
set { if (value == System.Drawing.Color.Transparent) this._backBrush = null; else this._backBrush = new SolidBrush(value); }
}
public System.Drawing.Color foregroundColour
{
set { if (value == System.Drawing.Color.Transparent) this._foreBrush = null; else this._foreBrush = new SolidBrush(value); }
}
// below are the two other Paint() and the other Edit() override. if you re-enable the code and set a
// breakpoint in each, you can test to see if either method gets called!
/*
protected override void Paint(Graphics g, Rectangle bounds, CurrencyManager source, int rowNum)
{
base.Paint(g, bounds, source, rowNum);
}
using System;
using System.Data;
using System.ComponentModel;
using System.Windows.Forms;
using System.Drawing;
namespace ss_manage
{
/// <summary>
/// This DataGrid Column class implements a ComboBox Column. The combo box is fed from a
/// table containing an collection of value objects and a string descriptor (the displayed
/// element). On losing focus, the combo box the current cell in the associated DataGrid
/// is updated with the current selected value object
/// </summary>
public class MyComboColumn : System.Windows.Forms.DataGridTextBoxColumn
{
// each column shares a single combobox
public ComboBox _cboColumn;
// data we save when the column is instantiated (no provision for subsequent rebinds)
private object _objSource;
private string _strMember;
private string _strValue;
// remember if we have bound the combobox to the parent datagrid control
private bool _bIsComboBound = false;
// data that describes the background and foreground colors used to paint the cell when not in edit mode
private Brush _backBrush = null;
private Brush _foreBrush = null;
// information picked up and held when we start to edit the source table
private int _iRowNum;
private CurrencyManager _cmSource;
/// <summary>
/// initialize the combobox column and take note of the data source/member/value used to fill the combobox
/// </summary>
/// <param name="objSource">bind Source for the combobox (typical is a DataTable object)</param>
/// <param name="strMember">bind for the combobox DisplayMember (typical is a Column Name within the Source)</param>
/// <param name="strValue">bind for the combobox ValueMember (typical is a Column Name within the Source)</param>
public MyComboColumn(object objSource, string strMember, string strValue, bool bUseDropDownList)
{
_objSource = objSource;
_strMember = strMember;
_strValue = strValue;
// create a new combobox object
_cboColumn = new ComboBox();
// set the data link to the source, member and value displayed by this combobox
_cboColumn.DataSource = _objSource;
_cboColumn.DisplayMember = _strMember;
_cboColumn.ValueMember = _strValue;
if (bUseDropDownList == true)
{
// we cannot create new countries through this column so disallow editing by making the combo a drop-down list
_cboColumn.DropDownStyle = ComboBoxStyle.DropDownList;
// Setting ReadOnly changes the behavior of the column so the 'leave' event fires whenever we
// change cell. The default behavior will not fire the 'leave' event when we up-arrow or
// down-arrow to the next row.
this.ReadOnly = true;
}
else
{
// because this is not an edit-through combo we are going to suppress key-strokes.
// notice this routine does not affect navigation or delete keys. The delete key
// allows us to select the null data value for this row
_cboColumn.KeyPress += new KeyPressEventHandler(_cboColumn_KeyPress);
this._cboColumn.DropDownStyle=ComboBoxStyle.Simple;
this.ReadOnly=true;
}
// we need to know when the combo box is getting closed so we can update the source data and
// hide the combobox control
_cboColumn.Leave += new EventHandler(cboColumn_Leave);
// make sure the combobox is invisible until we've set its correct position and dimensions
_cboColumn.Visible = false;
this.TextBox.MouseMove+= new MouseEventHandler(TextBox_MouseMove);
}
private void _cboColumn_KeyPress(object sender, KeyPressEventArgs e)
{
// mark all key events as handled to block editing of combobox entries
e.Handled = true;
}
protected override void Edit(CurrencyManager source, int rowNum, Rectangle bounds, bool readOnly, string instantText, bool cellIsVisible)
{
// the navigation path to the datagrid only exists after the column is added to the Styles
if (_bIsComboBound == false)
{
_bIsComboBound = true;
// important step here if we want to properly handle key events! the next step cannot
// be performed until the object is bound to the DataGrid (or an Exception must occur)
this.DataGridTableStyle.DataGrid.Controls.Add(_cboColumn);
}
// this data is used when the combo box loses focus
_iRowNum = rowNum;
_cmSource = source;
// synchronize the font size to the text box
_cboColumn.Font = this.TextBox.Font;
// we need to retrieve the current value and use this to set the combo box ahead of displaying it
object anObj = this.GetColumnValueAtRow(source, rowNum);
// set the combobox to the dimensions of the cell (do this each time because the user may have resized this column)
_cboColumn.Bounds = bounds;
// do not paint the control until we've set the correct position in the items list
_cboColumn.BeginUpdate();