要定製自已的DataGridView列樣式,事實上我們是要定製的是單元格的樣式,所謂列樣式,只是將同一列的所有單元格設定成相同格式而已,那麼如何做呢,有兩種方式:
(1)一種簡單的方式就是重寫DataGridViewCell的paint事件及其它觸發事件,從而得到想要的各種單元格效果,然後再簡單的重寫一個相應的DataGridViewColumn類,就可以了,但是這個方法需要自已去畫控件,對一般人來說還是一件麻煩的事.
(2)還有另一種方式,那就是在DataGridViewCell中放一個我們需要的控件,我們只需要改變這個控件,就可以達到改變單元格樣式的目的,這種方法就方便多了(當然,對這個控件是有要求的,它必須實現IDataGridViewEditingControl接口).
然後我們再重寫一個DataGridViewCell,在這裡可以控製當單元格進入編輯狀態時如何初始化這個用於編輯的控件.(在顯示狀態時如何控製控件的顯示,我還不知道.)
最後我們再重寫一個相應的DataGridViewColumn類就全搞定了.
下面以製作DataGridViewDateTimeColumn為例,介紹第(2)種方式的具體做法,相應的解析都在代碼裡面.
1.編寫DataGridViewDateTimeEditingControl類
這個類繼承自DateTimePicker,同時它必須實現IDataGridViewEditingControl接口,這個接口的定義如下:
public interface IDataGridViewEditingControl
{
// 取得或設定包含儲存格的 System.Windows.Forms.DataGridView。
DataGridView EditingControlDataGridView { get ; set ; }
// 取得或設定編輯器所修改之儲存格的格式化值。
object EditingControlFormattedValue { get ; set ; }
// 取得或設定裝載儲存格之父資料列的索引。
int EditingControlRowIndex { get ; set ; }
// 取得或設定值,指出編輯控制項的值是否與裝載儲存格的值不同。
bool EditingControlValueChanged { get ; set ; }
// 取得當滑鼠指標放在 System.Windows.Forms.DataGridView.EditingPanel 上方,但不在編輯控制項上方時所用的游標。
Cursor EditingPanelCursor { get ; }
// 取得或設定值,指出每當值變更時儲存格內容是否需要重新調整位置。
bool RepositionEditingControlOnValueChange { get ; }
// 變更控制項的使用者介面 (UI),使其與指定的儲存格樣式一致。
void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle);
// 判斷指定的按鍵是否為編輯控制項應該處理的標準輸入按鍵,或是 System.Windows.Forms.DataGridView 應該處理的特殊按鍵。
bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey);
// 擷取儲存格的格式化值。
object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context);
// 準備目前所選的儲存格來編輯。
void PrepareEditingControlForEdit( bool selectAll);
}
下面是DataGridViewDateTimeEditingControl 的源代碼:
{
protected int rowIndex;
protected DataGridView dataGridView;
protected bool valueChanged = false ;
public DataGridViewDateTimeEditingControl()
{
}
// 重寫基類事件OnValueChanged
protected override void OnValueChanged(EventArgs e)
{
// 估計這裡調用了GetEditingControlFormattedValue函數,
// 從而將控件的新值傳遞給單元格,做為單元格的新值
base .OnValueChanged(e);
// 通知DataGridView,控件所在單元格的值發生變化.
NotifyDataGridViewOfValueChange();
}
// 通知DataGridView,控件所在單元格的值發生變化
private void NotifyDataGridViewOfValueChange()
{
this .valueChanged = true ;
dataGridView.NotifyCurrentCellDirty( true );
}
#region IDataGridViewEditingControl接口的實現
/// <summary>
/// 獲取或設置儲存格所在的DataGridView
/// </summary>
public DataGridView EditingControlDataGridView
{
get
{
return this .dataGridView;
}
set
{
this .dataGridView = value;
}
}
/// <summary>
/// 獲取或設置儲存格格式化後的值
/// </summary>
public object EditingControlFormattedValue
{
get
{
return this .Text;
}
set
{
Text = value.ToString();
// 當控件的Text值發生變化時,通知DataGridView,控件所在的單元格的值也發生變化.
NotifyDataGridViewOfValueChange();
}
}
/// <summary>
/// 在Cell被編輯的時候光標顯示
/// </summary>
public Cursor EditingPanelCursor
{
get
{
return Cursors.IBeam;
}
}
/// <summary>
/// 取得或設定值,指出每當值變更時儲存格內容是否需要重新調整位置。
/// </summary>
public virtual bool RepositionEditingControlOnValueChange
{
get
{
return false ;
}
}
/// <summary>
/// 取得或設定儲存格所在行
/// </summary>
public int EditingControlRowIndex
{
get
{
return this .rowIndex;
}
set
{
this .rowIndex = value;
}
}
/// <summary>
/// 取得或設定值,指出編輯控制項的值是否與裝載儲存格的值不同。
/// </summary>
public bool EditingControlValueChanged
{
get
{
return valueChanged;
}
set
{
this .valueChanged = value;
}
}
/// <summary>
/// 擷取儲存格的格式化後的值。
/// </summary>
/// <param name="context"> 錯誤上下文 </param>
/// <returns></returns>
public virtual object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context)
{
return Text;
}
/// <summary>
/// 判斷指定的按鍵是否為編輯控制項應該處理的標準輸入按鍵,或是 System.Windows.Forms.DataGridView 應該處理的特殊按鍵。
/// </summary>
/// <param name="keyData"></param>
/// <param name="dataGridViewWantsInputKey"></param>
/// <returns></returns>
public bool EditingControlWantsInputKey(Keys key, bool dataGridViewWantsInputKey)
{
// Let the DateTimePicker handle the keys listed.
switch (key & Keys.KeyCode)
{
case Keys.Left:
case Keys.Up:
case Keys.Down:
case Keys.Right:
case Keys.Home:
case Keys.End:
case Keys.PageDown:
case Keys.PageUp:
return true ;
default :
return false ;
}
}
/// <summary>
/// 準備目前所選的儲存格來編輯。
/// </summary>
/// <param name="selectAll"></param>
public void PrepareEditingControlForEdit( bool selectAll)
{
}
/// <summary>
/// 變更控制項的介面 (UI),使其與當前單元格的樣式一致。
/// </summary>
/// <param name="dataGridViewCellStyle"></param>
public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle)
{
this .Font = dataGridViewCellStyle.Font;
this .CalendarForeColor = dataGridViewCellStyle.ForeColor;
this .CalendarMonthBackground = dataGridViewCellStyle.BackColor;
}
#endregion
}
2.編寫DataGridViewDateTimeCell類
{
private bool showUpDown;
public DataGridViewDateTimeCell()
{
}
/// <summary>
/// 在這裡初始化單元格編輯時的所用到的控件
/// </summary>
/// <param name="rowIndex"></param>
/// <param name="initialFormattedValue"></param>
/// <param name="dataGridViewCellStyle"></param>
public override void InitializeEditingControl( int rowIndex, object initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
{
base .InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle);
DataGridViewDateTimeEditingControl ctl = DataGridView.EditingControl as DataGridViewDateTimeEditingControl;
#region 設定DataGridViewDateTimeEditingControl控件的屬性
// 設定Value
ctl.Value = (DateTime) this .Value;
DataGridViewColumn dgvColumn = this .OwningColumn;
if (dgvColumn is DataGridViewDateTimeColumn)
{
DataGridViewDateTimeColumn dateTimeColumn = dgvColumn as DataGridViewDateTimeColumn;
//
// 設定ShowUpDown
//
ctl.ShowUpDown = this .ShowUpDown;
//
// 設定Format
//
switch (dateTimeColumn.DefaultCellStyle.Format)
{
case " d " :
ctl.Format = DateTimePickerFormat.Short;
break ;
case " D " :
ctl.Format = DateTimePickerFormat.Long;
break ;
case " f " :
ctl.Format = DateTimePickerFormat.Custom;
ctl.CustomFormat = " yyyy年M月d日 tt hh:mm " ;
break ;
case " F " :
ctl.Format = DateTimePickerFormat.Custom;
ctl.CustomFormat = " yyyy年M月d日 HH:mm:ss " ;
break ;
case " g " :
ctl.Format = DateTimePickerFormat.Custom;
ctl.CustomFormat = " yyyy/MM/dd tt hh:mm " ;
break ;
case " G " :
ctl.Format = DateTimePickerFormat.Custom;
ctl.CustomFormat = " yyyy/MM/dd HH:mm:ss " ;
break ;
case " t " :
ctl.Format = DateTimePickerFormat.Custom;
ctl.CustomFormat = " tt hh:mm " ;
break ;
case " T " :
ctl.Format = DateTimePickerFormat.Time;
ctl.CustomFormat = " HH:mm:ss " ;
break ;
case " M " :
ctl.Format = DateTimePickerFormat.Custom;
ctl.CustomFormat = " M月d日 " ;
break ;
default :
ctl.Format = DateTimePickerFormat.Custom;
ctl.CustomFormat = dateTimeColumn.DefaultCellStyle.Format;
break ;
}
}
#endregion
}
// 一個自定義屬性,用於改變控件的編輯方式
// 為什麼要這個屬性,DataGridViewDateTimeEditingControl繼承自DateTimePicker,DateTimePicker自已就有這個屬性,
// 直接改不就可以控製控件的外觀了嗎?這裡主要是為了將該屬性暴露出來,從而可以在本控件以外進行修改.
public virtual bool ShowUpDown
{
get
{
return this .showUpDown;
}
set
{
this .showUpDown = value;
}
}
// 編輯狀態時控件的類型
public override Type EditType
{
get
{
return typeof (DataGridViewDateTimeEditingControl);
}
}
// 單元格值的類型
public override Type ValueType
{
get
{
return typeof (DateTime);
}
}
// 單元格默認值
public override object DefaultNewRowValue
{
get
{
return DateTime.Now;
}
}
}
3.編寫DataGridViewDateTimeColumn 類
{
private bool showUpDown ;
public DataGridViewDateTimeColumn() : base ( new DataGridViewDateTimeCell())
{
}
public override DataGridViewCell CellTemplate
{
get
{
return base .CellTemplate;
}
set
{
if (value != null && ! value.GetType().IsAssignableFrom( typeof (DataGridViewDateTimeCell)))
{
throw new InvalidCastException( " 不是DataGridViewDateTimeCell " );
}
base .CellTemplate = value;
}
}
// 要實現自定義屬性設計時的保存必須同時重寫Clone方法
// 在這裡我們自定義了一個屬性ShowUpDown,所以要重寫該方法
public override object Clone()
{
DataGridViewDateTimeColumn col = (DataGridViewDateTimeColumn) base .Clone();
col.ShowUpDown = this .showUpDown;
return col;
}
// 自定義的屬性
// 在Cell中存在的屬性,在Column中我們一般也應該有相應的屬性.
public bool ShowUpDown
{
get
{
return showUpDown;
}
set
{
if ( this .showUpDown != value)
{
this .showUpDown = value;
DataGridViewDateTimeCell dateTimeCell = (DataGridViewDateTimeCell) this .CellTemplate;
dateTimeCell.ShowUpDown = value;
if ( this .DataGridView != null && this .DataGridView.Rows != null )
{
int rowCount = this .DataGridView.Rows.Count;
for ( int x = 0 ; x < rowCount; x ++ )
{
DataGridViewCell dataGridViewCell = this .DataGridView.Rows.SharedRow(x).Cells[x];
if (dataGridViewCell is DataGridViewDateTimeCell)
{
dateTimeCell = (DataGridViewDateTimeCell)dataGridViewCell;
dateTimeCell.ShowUpDown = value;
}
}
}
}
}
}
}