A:設置ReadOnly屬性,可以設置的對象包括DataGridViewRow(行)、DataGridViewColumn(列)、DataGridViewCell(單元格)以及自身DataGridView對象均可設置ReadOnly屬性來限制單元格的編輯狀態。
擴展:需要注意的是,當DataGridView通過DataSource綁定數據自動生成行列時,如果直接在Form的構造函數初始化界面InitializeComponent後直接設置ReadOnly屬性,會造成一些意想不到的效果……
1 public MainForm()
2 {
3 InitializeComponent()
4
5 Application.DoEvents()
6 dataGridView.DataSource = Person.GetPersons()
7 dataGridView[0, 0].ReadOnly = true
8 dataGridView.Rows[2].ReadOnly = true
9 dataGridView.Columns[1].ReadOnly = true
10 }
此時對DataGridViewCell、DataGridViewRow的ReadOnly設置無效,而對DataGridViewColumn的ReadOnly設置有效。
另外,ReadOnly屬性只是限制用戶在界面上對單元格內容編輯的限制,並不影響在編程代碼中對該單元格的編輯以及刪除行列操作。
當然,你也可以在CellBeginEdit事件中對單元格進行判斷,然後直接結束編輯即可,如下:
1 dataGridView.CellBeginEdit += (sender, e) =>
2 {
3 if (e.RowIndex == 0 && e.ColumnIndex == 0)
4 {
5 e.Cancel = true
6 // 或者
7 // dataGridView.EndEdit();
8 }
9 }
A:DataGridView不支持設置單元格的不可用狀態,所以采用折中辦法,使該“禁用”單元格的選中狀態和其背景顏色相同,給人暗示性的外觀提示該單元格“禁用”。
有一種便捷的方式,就是將該“禁用”單元格的選中顏色設置成非選中顏色,即如果未選中前是白底黑字,則將該“禁用”單元格的選中狀態也改成白底黑字即可,對單元格、行和列均適用,舉例如下:
1 dataGridView[2, 2].Style.SelectionBackColor = Color.White 2 dataGridView[2, 2].Style.SelectionForeColor = Color.Black 3 4 dataGridView.Rows[1].DefaultCellStyle.SelectionBackColor = Color.White 5 dataGridView.Rows[1].DefaultCellStyle.SelectionForeColor = Color.Black 6 7 dataGridView.Columns[0].DefaultCellStyle.SelectionBackColor = Color.White 8 dataGridView.Columns[0].DefaultCellStyle.SelectionForeColor = Color.Black
需要注意的是,同Q1中一樣,在InitializeComponent方法後面直接操作,其中對單元格的設置無效,對行、列的設置有效!!
但是這種方法對文本內容的單元有效,對於DataGridViewButtonColumn、DataGridViewCheckBoxColumn、DataGridViewComboBoxColumn等其他特殊列就沒效果了,畢竟對於特殊列,禁用單元格就是要禁用其中的特殊控件,這時候就需要重寫其中的單元格模版了,以DataGridViewButtonColumn為例,代碼如下:

public class DataGridViewButtonColumnExt : DataGridViewButtonColum
{
public DataGridViewButtonColumnExt()
{
this.CellTemplate = new DataGridViewButtonCellExt()
}
}
public class DataGridViewButtonCellExt : DataGridViewButtonCell
{
private bool _Enabled;// 設置該單元格是否可用
/// <summary>
/// 單元格是否可用
/// </summary>
public bool Enabled
{
get
{
return _Enabled
}
set
{
_Enabled = value
}
}
public override object Clone()
{
DataGridViewButtonCellExt cell =(DataGridViewButtonCellExt)base.Clone()
cell.Enabled = this.Enabled
return cell
}
public DataGridViewButtonCellExt()
{
this._Enabled = true
}
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds,
int rowIndex, DataGridViewElementStates elementState, object value,
object formattedValue, string errorText, DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
{
if (!this._Enabled)
{
// 繪制背景
if ((paintParts & DataGridViewPaintParts.Background) == DataGridViewPaintParts.Background)
{
SolidBrush cellBackground = new SolidBrush(cellStyle.BackColor)
graphics.FillRectangle(cellBackground, cellBounds)
cellBackground.Dispose()
}
// 繪制邊框
if ((paintParts & DataGridViewPaintParts.Border) == DataGridViewPaintParts.Border)
{
PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle)
}
Rectangle buttonArea = cellBound
Rectangle buttonAdjustment = this.BorderWidths(advancedBorderStyle)
buttonArea.X += buttonAdjustment.X
buttonArea.Y += buttonAdjustment.Y
buttonArea.Height -= buttonAdjustment.Height
buttonArea.Width -= buttonAdjustment.Width
// 繪制按鈕控件
ButtonRenderer.DrawButton(graphics, buttonArea, PushButtonState.Disabled)
// 繪制文本內容
if (this.FormattedValue is String)
{
TextRenderer.DrawText(graphics, (string)this.FormattedValue,
this.DataGridView.Font, buttonArea, SystemColors.GrayText)
}
}
else
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue,
errorText, cellStyle, advancedBorderStyle, paintParts)
}
}
}
View Code
下面是CheckBox列的重寫例子,因為復選框有兩種禁用效果,一種選中時禁用,一種是未選中時禁用,所以加了一個IsChecked屬性:

public class DataGridViewCheckBoxColumnExt : DataGridViewCheckBoxColum
{
public DataGridViewCheckBoxColumnExt()
{
this.CellTemplate = new DataGridViewCheckBoxCellExt()
}
}
public class DataGridViewCheckBoxCellExt : DataGridViewCheckBoxCell
{
private bool _Enable
private bool _IsChecked
/// <summary>
/// 是否選中
/// </summary>
public bool IsChecked
{
get
{
return _IsChecked
}
set
{
_IsChecked = value
}
}
/// <summary>
/// 是否可用
/// </summary>
public bool Enable
{
get
{
return _Enable
}
set
{
_Enable = value
}
}
public DataGridViewCheckBoxCellExt()
{
_Enable = true
_IsChecked = false
}
public override object Clone()
{
DataGridViewCheckBoxCellExt dgvcce = (DataGridViewCheckBoxCellExt)base.Clone()
dgvcce.Enable = this.Enable
dgvcce.IsChecked = this.IsChecked
return dgvcce
}
protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds,
int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue,
string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
if (!_Enable)
{
// 繪制背景
if ((paintParts & DataGridViewPaintParts.Background) == DataGridViewPaintParts.Background)
{
SolidBrush cellBackground = new SolidBrush(cellStyle.BackColor)
graphics.FillRectangle(cellBackground, cellBounds)
cellBackground.Dispose()
}
// 繪制邊框
if ((paintParts & DataGridViewPaintParts.Border) == DataGridViewPaintParts.Border)
{
PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle)
}
Point pos = cellBounds.Locatio
// 調整位置居中
pos.X = pos.X + cellBounds.Width / 2 - 7
pos.Y = pos.Y + cellBounds.Height / 2 - 7
// 繪制按鈕控件
CheckBoxRenderer.DrawCheckBox(graphics, pos,
IsChecked ? CheckBoxState.CheckedDisabled : CheckBoxState.UncheckedDisabled)
}
else
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value,
formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)
}
}
}
View Code
A:參考網上查到的資料,將文本列(DataGridViewTextBoxColum)中的文本向右偏移,然後在前面置入圖片;

public class TextAndImageColumn : DataGridViewTextBoxColum
{
private Image m_ImageValue
private Size m_ImageSize
public TextAndImageColumn()
{
this.CellTemplate = new TextAndImageCell()
}
public override object Clone()
{
TextAndImageColumn c = base.Clone() as TextAndImageColum
c.m_ImageValue = this.m_ImageValue
c.m_ImageSize = this.m_ImageSize
return c
}
public Image Image
{
get
{
return this.m_ImageValue
}
set
{
if (this.Image != value)
{
this.m_ImageValue = value
this.m_ImageSize = value.Size
if (this.InheritedStyle != null)
{
Padding inheritedPadding = this.InheritedStyle.Padding
this.DefaultCellStyle.Padding = new Padding(m_ImageSize.Width,
inheritedPadding.Top, inheritedPadding.Right,
inheritedPadding.Bottom)
}
}
}
}
public Size ImageSize
{
get
{
return m_ImageSize
}
set
{
m_ImageSize = value
}
}
private TextAndImageCell TextAndImageCellTemplate
{
get
{
return this.CellTemplate as TextAndImageCell
}
}
}
public class TextAndImageCell : DataGridViewTextBoxCell
{
private Image m_ImageValue
private Size m_ImageSize
public override object Clone()
{
TextAndImageCell c = base.Clone() as TextAndImageCell
c.m_ImageValue = this.m_ImageValue
c.m_ImageSize = this.m_ImageSize
return c
}
public Image Image
{
get
{
if (this.OwningColumn == null || this.OwningTextAndImageColumn == null)
{
return m_ImageValue
}
else if (this.m_ImageValue != null)
{
return this.m_ImageValue
}
else
{
return this.OwningTextAndImageColumn.Image
}
}
set
{
if (this.m_ImageValue != value)
{
this.m_ImageValue = value
this.m_ImageSize = value.Size
Padding inheritedPadding = this.InheritedStyle.Padding
this.Style.Padding = new Padding(m_ImageSize.Width,
inheritedPadding.Top, inheritedPadding.Right,
inheritedPadding.Bottom)
}
}
}
protected override void Paint(Graphics graphics, Rectangle clipBounds,
Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState,
object value, object formattedValue, string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
// Paint the base content
base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState,
value, formattedValue, errorText, cellStyle,
advancedBorderStyle, paintParts)
if (this.Image != null)
{
// Draw the image clipped to the cell.
System.Drawing.Drawing2D.GraphicsContainer container = graphics.BeginContainer()
graphics.SetClip(cellBounds)
graphics.DrawImageUnscaled(this.Image, cellBounds.Location)
graphics.EndContainer(container)
}
}
private TextAndImageColumn OwningTextAndImageColum
{
get
{
return this.OwningColumn as TextAndImageColum
}
}
}
View Code
還有一種實現方式是在CellPainting事件中對指定單元格進行圖文繪制,參考百度文庫
A:見 DataGridView中DataGridViewComboBox的可編輯 。
還有一種根據參考資料1提供的方法,更簡捷,就是在CellValidating事件中將新編輯的內容添加到Items集合中,在EditingControlShowing事件中將下拉框類型DropDownStyle設置成ComboBoxStyle.DropDown,使用戶可以進入編輯狀態,代碼如下:
1 private void dgv4_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
2 {
3 try
4 {
5 if (dgv4.CurrentCellAddress.X == 4)
6 {
7 ComboBox cb = e.Control as ComboBox;
8 if (cb != null)
9 {
10 cb.DropDownStyle = ComboBoxStyle.DropDown;
11 }
12 }
13 }
14 catch (Exception ex)
15 {
16 MessageBox.Show(ex.Message);
17 }
18 }
19
20 private void dgv4_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
21 {
22 try
23 {
24 if (e.ColumnIndex == 4)
25 {
26 DataGridViewComboBoxColumn dgvcbc = (DataGridViewComboBoxColumn)dgv4.Columns[4];
27 if (!dgvcbc.Items.Contains(e.FormattedValue))
28 {
29 dgvcbc.Items.Add(e.FormattedValue);
30 }
31 }
32 }
33 catch (Exception ex)
34 {
35 MessageBox.Show(ex.Message);
36 }
37 }
A:分綁定數據和非綁定數據兩種情況處理。
如果綁定的數據源(如DataView)支持多列排序,則DataGridView在綁定數據後會保留數據源排序後的結果,但是只有第一個進行排序的列會在DataGridView的顯示排序標記。而且,DataGridView的SortedColumn屬性也只返回第一個排序列。
如果數據源實現了IBindingListView接口,並提供了對Sort屬性的支持,那麼該數據源就可以支持多列排序。為了彌補上面提到的只標記了第一排序列的缺陷,可以手動對進行排序的列設置SortGlyphDirection屬性來標記。
1 BindingSource bindingSource = new BindingSource();
2 dgv4.AutoGenerateColumns = false;
3 dgv4.DataSource = bindingSource;
4
5 DataTable dt = new DataTable();
6 dt.Columns.Add("C1", typeof(int));
7 dt.Columns.Add("C2", typeof(string));
8 dt.Columns.Add("C3", typeof(string));
9
10 dt.Rows.Add(1, "1", "Test1");
11 dt.Rows.Add(2, "2", "Test2");
12 dt.Rows.Add(2, "2", "Test1");
13 dt.Rows.Add(3, "3", "Test3");
14 dt.Rows.Add(4, "4", "Test4");
15 dt.Rows.Add(4, "4", "Test3");
16
17 DataView view = dt.DefaultView;
18 view.Sort = "C2 ASC,C3 DESC";
19 bindingSource.DataSource = view;
20
21 DataGridViewTextBoxColumn col0 = new DataGridViewTextBoxColumn();
22 col0.DataPropertyName = "C1";
23 dgv4.Columns.Add(col0);
24 col0.SortMode = DataGridViewColumnSortMode.Programmatic;
25 col0.HeaderCell.SortGlyphDirection = SortOrder.None;
26
27 DataGridViewTextBoxColumn col1 = new DataGridViewTextBoxColumn();
28 col1.DataPropertyName = "C2";
29 dgv4.Columns.Add(col1);
30 col1.SortMode = DataGridViewColumnSortMode.Programmatic;
31 col1.HeaderCell.SortGlyphDirection = SortOrder.Ascending;
32
33 DataGridViewTextBoxColumn col2 = new DataGridViewTextBoxColumn();
34 col2.DataPropertyName = "C3";
35 dgv4.Columns.Add(col2);
36 col2.SortMode = DataGridViewColumnSortMode.Programmatic;
37 col2.HeaderCell.SortGlyphDirection = SortOrder.Descending;
需要注意的是,對SortGlyphDirection屬性的設置要在DataGridView綁定DataSource後面操作,否則會不生效。
上面代碼來自資料參考2的,可以簡化成:

DataTable dt = new DataTable();
dt.Columns.Add("C1", typeof(int));
dt.Columns.Add("C2", typeof(string));
dt.Columns.Add("C3", typeof(string));
dt.Rows.Add(1, "1", "Test1");
dt.Rows.Add(2, "2", "Test2");
dt.Rows.Add(2, "2", "Test1");
dt.Rows.Add(3, "3", "Test3");
dt.Rows.Add(4, "4", "Test4");
dt.Rows.Add(4, "4", "Test3");
DataView view = dt.DefaultView;
view.Sort = "C2 ASC,C3 DESC";
dgv4.DataSource = dt;
dgv4.Columns[1].SortMode = DataGridViewColumnSortMode.Programmatic;
dgv4.Columns[1].HeaderCell.SortGlyphDirection = SortOrder.Ascending;
dgv4.Columns[2].SortMode = DataGridViewColumnSortMode.Programmatic;
dgv4.Columns[2].HeaderCell.SortGlyphDirection = SortOrder.Descending;
View Code
為了提供對多個列排序的支持,可以通過處理SortCompare事件,或者調用重載的Sort ( IComparer ) 方法以更靈活的方式進行排序。
2.1、SortCompare事件
private void dgv4_SortCompare(object sender, DataGridViewSortCompareEventArgs e)
{
try
{
e.SortResult = String.Compare(e.CellValue1.ToString(), e.CellValue2.ToString());
if (e.SortResult == 0 && e.Column.Name != "ID")
{
e.SortResult = string.Compare(
dgv4.Rows[e.RowIndex1].Cells["ID"].Value.ToString(),
dgv4.Rows[e.RowIndex2].Cells["ID"].Value.ToString());
}
e.Handled = true;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
上面的例子表示當你點擊列頭對某一列進行排序時,如果值相同時,則會按照對應ID值進行排序;所以如果要支持多列排序,在該事件裡處理即可。
2.2、IComparer 接口
樓主擴展了資料裡提供的參考例子,改成通用的多列排序接口實現,

1 public class RowComparer : IComparer
2 {
3 private Dictionary<string, int> m_SortList;
4
5 /// <summary>
6 /// 排序字符串,格式:(ColName1 AES,ColName2 DESC,ColName3 AES,...)
7 /// </summary>
8 public string Sort
9 {
10 get;
11 set;
12 }
13
14 /// <summary>
15 /// 構造函數,初始化排序條件
16 /// </summary>
17 public RowComparer(string sort)
18 {
19 Sort = sort;
20 try
21 {
22 string[] tmp = Sort.Split(',');
23 m_SortList = new Dictionary<string, int>();
24 for (int i = 0; i < tmp.Length; i++)
25 {
26 string[] tmp2 = tmp[i].Split(new char[] { ' ' },
27 StringSplitOptions.RemoveEmptyEntries);
28 string colName = tmp2[0].ToLower();
29 int sortType = tmp2[1].ToLower().Equals("AES") ? 1 : -1;
30 if (m_SortList.ContainsKey(colName))
31 {
32 m_SortList[colName] = sortType;
33 }
34 else
35 {
36 m_SortList.Add(colName, sortType);
37 }
38 }
39 }
40 catch (Exception ex)
41 {
42 throw new Exception(ex.Message);
43 }
44 }
45
46 #region IComparer 成員
47
48 public int Compare(object x, object y)
49 {
50 int compareResult = 0;// 比較結果
51 int sortMode = 0;// 排序方式
52 try
53 {
54 DataGridViewRow dgvr1 = (DataGridViewRow)x;
55 DataGridViewRow dgvr2 = (DataGridViewRow)y;
56 foreach (string colName in m_SortList.Keys)
57 {
58 compareResult = string.Compare(dgvr1.Cells[colName].Value.ToString(),
59 dgvr2.Cells[colName].Value.ToString());
60 sortMode = m_SortList[colName];
61 if (compareResult != 0)
62 {
63 break;
64 }
65 }
66 }
67 catch (Exception ex)
68 {
69 MessageBox.Show(ex.Message);
70 }
71
72 return compareResult * sortMode;
73 }
74
75 #endregion
76 }
View Code
Sort屬性采用DataView的Sort屬性設置,然後在RowComparer構造函數對排序字符串進行處理,最後在接口方法Compare中依先後順序逐級排序;
A:當DataGridView綁定List數據源時,對List進行操作後並不會實時更新到DataGridView上,這時候采用BindingList就可以很好的解決問題。BindingList類可以用作創建雙向數據綁定機制的基類。BindingList提供IBindingList接口的具體泛型實現,這樣就不必實現完整的IBindingList接口了。
BindingList還可以通過擴展的AddNew方法支持工廠創建的示例;通過EndNew和CancelNew方法實現新項的事務性提交和回滾。
A:用戶選中一行後按Delete鍵會觸發UserDeletingRow事件(當然,前提是要設置DataGridView的AllowUserToDeleteRows屬性為True才可以),在該事件裡提示用戶是否刪除當前選中記錄即可。
private void dgv4_UserDeletingRow(object sender, DataGridViewRowCancelEventArgs e)
{
try
{
if (!e.Row.IsNewRow)
{
if (MessageBox.Show("確定刪除當前選中數據?", "刪除",
MessageBoxButtons.YesNo, MessageBoxIcon.Question,
MessageBoxDefaultButton.Button2)
== System.Windows.Forms.DialogResult.No)
{
e.Cancel = true;
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
A:諸如DataGridViewButtonColumn列裡的Button,DataGridViewCheckBoxColumn列裡的CheckBox等等,要給Button或CheckBox控件添加事件處理函數,則可以通過實現DataGridView的EditingControlShowing事件,該事件是在單元格進入編輯模式時觸發,可以處理執行該編輯控件的自定義初始化。它的第二個參數DataGridViewEditingControlShowingEventArgs類型,其Control屬性就是該單元格內的編輯控件了。拿DataGridViewComboBoxColumn列裡的ComboBox事件舉個例子:

private void dgv4_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
try
{
ComboBox cb = e.Control as ComboBox;
if (cb != null)
{
cb.SelectedIndexChanged -= new EventHandler(cb_SelectedIndexChanged);
cb.SelectedIndexChanged += cb_SelectedIndexChanged;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void cb_SelectedIndexChanged(object sender, EventArgs e)
{
MessageBox.Show("Selected Index Changed!");
}
View Code需要注意的是,在EditingControlShowing事件裡對編輯控件進行事件綁定時,要防止其添加多個相同的事件處理函數,所以在綁定事件前可以先移除相應的事件處理函數。
A:可以設置DataGridView的AutoSizeColumnsMode屬性,設置為DataGridViewAutoSizeColumnsMode.Fill,此時列寬會自動調整到使所有列寬精確填充控件的顯示區域。當然,你可以通過設置每一列的DataGridViewColumn.FillWeight屬性來設置每一列的相對寬度。
如果只是想把最後一列填充剩下的空間,而前面那些列都是固定大小的,那可以直接設置最後一列的DataGridViewColumn.AutoSizeMode的屬性為 DataGridViewAutoSizeColumnMode.Fill 即可。
A:設置DataGridViewColumn.DefaultCellStyle.WrapMode = DataGridViewTriState.True;
A:設置Image列的 dataGridView.DefaultCellStyle.NullValue = null;
1、http://www.cnblogs.com/xiaofengfeng/archive/2011/04/16/2018504.html (主要參考)
2、http://blogs.msdn.com/b/jfoscoding/archive/2005/11/17/494012.aspx
3、https://msdn.microsoft.com/zh-cn/library/ms132679.aspx#Mtps_DropDownFilterTextBindingList
未完待續……