前面的博文:WPF+SQL Server 2008 TaskVision Demo小結,寫了用WPF和SQL Server 2008實現這個Demo時候遇到的一些有必要說明的地方。如SQL Server的相關設置問題,DataGrid的Binding等...
畢竟那是WPF,其為我們簡化了頁面的表示,如提供了DataGrid控件擴展了Winform下的DataGridView控件!
那么我們用Winform如何實現相同的功能呢?
下面DebugLZQ來總結下Winform中的DataGridView的使用。
一般用過datagridview控件的人都知道,該控件提供了6種不同的column,vs08、vs10、vs12都是這樣,如下:

DebugLZQ寫了一個小例子來展示這些column的使用。
我在一個Winform頁面上添加了一個datagridview控件,並通過編輯器,添加了7個column,這些column包含了以上所有的6中DataGridViewColumn。如下:

我們來看下用法:
private void Form3_Load(object sender, EventArgs e) { LoadData(); dataGridView1.AutoGenerateColumns = false; } /// <summary> //1.DataGridView各種Column使用 //可添加CellContentClick事件根據列進行相應的處理 /// </summary> private void LoadData() { //演示DataGridView各種Colum使用 dataGridView1.AutoGenerateColumns = false; DataTable dataTable = SQLHelper.GetDataTable("select * from tb_TaskInfo"); //dataGridView1.DataSource = dataTable; dataGridView1.Rows.Add(dataTable.Rows.Count); for (int i = 0; i < dataTable.Rows.Count; i++) { dataGridView1.Rows[i].Cells["Id"].Value = dataTable.Rows[i].ItemArray[0].ToString();//DataGridViewTextBoxColumn dataGridView1.Rows[i].Cells["PLevel"].Value = Image.FromFile(dataTable.Rows[i].ItemArray[9].ToString());//DataGridViewImageColumn dataGridView1.Rows[i].Cells["Distribution"].Value = dataTable.Rows[i].ItemArray[2].ToString();//DataGridViewLinkColumn dataGridView1.Rows[i].Cells["Abstract"].Value = dataTable.Rows[i].ItemArray[3].ToString(); dataGridView1.Rows[i].Cells["State"].Value = dataTable.Rows[i].ItemArray[4].ToString();//DataGridViewComboBoxColumn if (dataTable.Rows[i].ItemArray[4].ToString() == "Open") { dataGridView1.Rows[i].Cells["State2"].Value = true;//DataGridViewCheckBoxColumn } else { dataGridView1.Rows[i].Cells["State2"].Value = false; } dataGridView1.Rows[i].Cells["Rate"].Value = dataTable.Rows[i].ItemArray[5].ToString() + "%";//DataGridViewButtonColumn } }
需要對鼠標點擊事件進行處理的話,我們可以添加類似CellContentClick事件,定位具體列、單元格等進行相應的處理。
其運行效果如下:

其數據庫表數據格式如下:

上面的運行圖只是演示下如何用自帶的各種Column,奇丑無比不談,還沒有實現相應的功能,比如說我們最后一列的百分。
一般情況下,我們可以在使用datagridview自帶Column的基礎上,通過datagridview的cellpainting事件,來進行處理,實現一些特殊的功能。
添加dataGridView1的CellPainting事件,事件處理如下:
//2.有特別需要的地方用CellPainting事件進行重繪 private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) { if (e.RowIndex >= 0 && e.ColumnIndex == 6) { int rate = Convert.ToInt32(dataGridView1.Rows[e.RowIndex].Cells["Rate"].Value.ToString().Substring(0, dataGridView1.Rows[e.RowIndex].Cells["Rate"].Value.ToString().Length - 1)); Rectangle newRect = new Rectangle(e.CellBounds.X, e.CellBounds.Y, rate, e.CellBounds.Height); using (Brush gridBrush = new SolidBrush(dataGridView1.GridColor), backColorBrush = new SolidBrush(e.CellStyle.BackColor)) { using (Pen gridLinePen = new Pen(gridBrush, 2)) { // Erase the cell. e.Graphics.FillRectangle(backColorBrush, e.CellBounds); //划線 Point p1 = new Point(e.CellBounds.Left + e.CellBounds.Width, e.CellBounds.Top); Point p2 = new Point(e.CellBounds.Left + e.CellBounds.Width, e.CellBounds.Top + e.CellBounds.Height); Point p3 = new Point(e.CellBounds.Left, e.CellBounds.Top + e.CellBounds.Height); Point[] ps = new Point[] { p1, p2, p3 }; e.Graphics.DrawLines(gridLinePen, ps); //畫多邊形 e.Graphics.DrawRectangle(Pens.LightBlue, newRect); e.Graphics.FillRectangle(Brushes.LightBlue, newRect); //畫字符串 e.Graphics.DrawString(rate.ToString() + "%", e.CellStyle.Font, Brushes.Crimson, e.CellBounds.Left + 20, e.CellBounds.Top + 5, StringFormat.GenericDefault); e.Handled = true; } } } }
效果如下:
一般的用法就是這樣。
界面丑?
我們來美化下:

主要的美化方法是:
去掉自動生成的第一列 :RowHeadersVisible=false;
隔行變色:設置以下2個屬性
dataGridViewX1.RowsDefaultCellStyle.BackColor ;
dataGridViewX1.AlternatingRowsDefaultCellStyle.BackColor ;
設置行選中:SelectionMode=FullRowSelect;
禁止改變列高:AllowUserToResizeRows = False
鼠標經過改變形狀及顏色:后面有代碼。
都是一些datagridview的小細節,無傷大雅,重點不在這。內在的東西才最重要!
還是有點丑?
再來美化下,加個皮膚吧----這個DebugLZQ千米的博文有介紹。
效果如下:

界面這下差不多OK了。是不是有點像WPF搞得?
貌似有點跑的遠了,光盯着界面了。我們來總結下:
datagridview為我們提供了6種自帶的Column,不能滿足要求的話,我們可以通過datagridview的CellPainting事件繪制,來實現一些特別的需求。
當然針對上面的Form2,DebugLZQ只是用了DataGridViewTextBoxColumn+CellPainting來實現的。
實現過程如下:
1.定義DataGridView的列,注意這個DataPropertyName:設置顯示DataTable中的列名。

注意設置:dataGridView1.AutoGenerateColumns = false;來禁止datagridView自動為我們添加列。
2.數據綁定及CellPainting事件處理如下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace TaskVision_V_1_WinForm { public partial class Form2 : Form { public Form2() { InitializeComponent(); imageComboBoxUserControl1.Items.Add(new ImageComboBoxUserControl.ItemEx("Major", Image.FromFile("Images/Major.gif"))); imageComboBoxUserControl1.Items.Add(new ImageComboBoxUserControl.ItemEx("Medium", Image.FromFile("Images/Medium.gif"))); imageComboBoxUserControl1.Items.Add(new ImageComboBoxUserControl.ItemEx("Minor", Image.FromFile("Images/Minor.gif"))); } private void Form2_Load(object sender, EventArgs e) { dataGridView1.AutoGenerateColumns = false; DataTable dataTable = SQLHelper.GetDataTable("select * from tb_TaskInfo"); dataGridView1.DataSource = dataTable; } private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e) { //第2列改成顯示圖片 if (e.RowIndex >= 0 && e.ColumnIndex == 1) { if (dataGridView1.Rows[e.RowIndex].Cells["PLevel"].Value == DBNull.Value) return; string imagePath = "Images/" + dataGridView1.Rows[e.RowIndex].Cells["PLevel"].Value + ".gif"; if (imagePath == "Images/.gif") return; Image img = Image.FromFile(imagePath); Rectangle newRect = new Rectangle(e.CellBounds.X, e.CellBounds.Y, e.CellBounds.Height, e.CellBounds.Height); using (Brush gridBrush = new SolidBrush(dataGridView1.GridColor), backColorBrush = new SolidBrush(e.CellStyle.BackColor)) { using (Pen gridLinePen = new Pen(gridBrush, 2)) { // Erase the cell. e.Graphics.FillRectangle(backColorBrush, e.CellBounds); //划線 Point p1 = new Point(e.CellBounds.Left + e.CellBounds.Width, e.CellBounds.Top); Point p2 = new Point(e.CellBounds.Left + e.CellBounds.Width, e.CellBounds.Top + e.CellBounds.Height); Point p3 = new Point(e.CellBounds.Left, e.CellBounds.Top + e.CellBounds.Height); Point[] ps = new Point[] { p1, p2, p3 }; e.Graphics.DrawLines(gridLinePen, ps); //畫圖標 e.Graphics.DrawImage(img, newRect); ////畫字符串 //e.Graphics.DrawString(dataGridView1.Rows[e.RowIndex].Cells["PLevel"].Value.ToString(), e.CellStyle.Font, Brushes.Crimson, // e.CellBounds.Left + 20, e.CellBounds.Top + 5, StringFormat.GenericDefault); e.Handled = true; } } } //第6列改成圖形百分比 else if (e.RowIndex >= 0 && e.ColumnIndex == 5) { int rate = Convert.ToInt32(dataGridView1.Rows[e.RowIndex].Cells["Rate"].Value); Rectangle newRect = new Rectangle(e.CellBounds.X, e.CellBounds.Y, rate, e.CellBounds.Height); using (Brush gridBrush = new SolidBrush(dataGridView1.GridColor), backColorBrush = new SolidBrush(e.CellStyle.BackColor)) { using (Pen gridLinePen = new Pen(gridBrush, 2)) { // Erase the cell. e.Graphics.FillRectangle(backColorBrush, e.CellBounds); //划線 Point p1 = new Point(e.CellBounds.Left + e.CellBounds.Width, e.CellBounds.Top); Point p2 = new Point(e.CellBounds.Left + e.CellBounds.Width, e.CellBounds.Top + e.CellBounds.Height); Point p3 = new Point(e.CellBounds.Left, e.CellBounds.Top + e.CellBounds.Height); Point[] ps = new Point[] { p1, p2, p3 }; e.Graphics.DrawLines(gridLinePen, ps); //畫多邊形 e.Graphics.DrawRectangle(Pens.LightBlue, newRect); e.Graphics.FillRectangle(Brushes.LightBlue, newRect); //畫字符串 e.Graphics.DrawString(rate.ToString() + "%", e.CellStyle.Font, Brushes.Crimson, e.CellBounds.Left + 20, e.CellBounds.Top + 5, StringFormat.GenericDefault); e.Handled = true; } } } } private void button1_Click(object sender, EventArgs e) { //get/set imageComboBoxUserControl1.SelectedIndex = 2; MessageBox.Show(imageComboBoxUserControl1.SelectedItem.ToString()); } ///////////////////////////////////// //設置鼠標經過改變顏色 Color colorTmp = Color.White; // 用來記錄先前的顏色值 private void dataGridView1_CellMouseEnter(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex >= 0) { colorTmp = dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor; dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor = Color.Red; } } private void dataGridView1_CellMouseLeave(object sender, DataGridViewCellEventArgs e) { if (e.RowIndex >= 0) { dataGridView1.Rows[e.RowIndex].DefaultCellStyle.BackColor = colorTmp; } } } }
頁面中多了一些代碼?是LZ為了模仿WPF的ComboBox自定義的ImageComboBoxUserControl控件,
該自定義ImageComboBoxUserControl控件,讓ComboBox中同時顯示圖片和文字。

其源碼如下,控件的使用方法見上面的代碼。
using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Data; using System.Linq; using System.Text; using System.Windows.Forms; using System.Drawing.Drawing2D; namespace TaskVision_V_1_WinForm { public partial class ImageComboBoxUserControl : ComboBox { public ImageComboBoxUserControl() { //InitializeComponent(); DrawMode = System.Windows.Forms.DrawMode.OwnerDrawFixed; DropDownStyle = ComboBoxStyle.DropDownList; ItemHeight = 30; Width = 80; } protected override void OnDrawItem(DrawItemEventArgs e) { if (Items.Count == 0 || e.Index == -1) return; if ((e.State & DrawItemState.Selected) != 0) { //漸變畫刷 LinearGradientBrush brush = new LinearGradientBrush(e.Bounds, Color.FromArgb(255, 251, 237), Color.FromArgb(255, 236, 181), LinearGradientMode.Vertical); //填充區域 Rectangle borderRect = new Rectangle(3, e.Bounds.Y, e.Bounds.Width - 5, e.Bounds.Height - 2); e.Graphics.FillRectangle(brush, borderRect); //畫邊框 Pen pen = new Pen(Color.FromArgb(229, 195, 101)); e.Graphics.DrawRectangle(pen, borderRect); } else { SolidBrush brush = new SolidBrush(Color.FromArgb(255, 255, 255)); e.Graphics.FillRectangle(brush, e.Bounds); } //獲得項圖片,繪制圖片 ItemEx item = (ItemEx)Items[e.Index]; Image img = item.Image; //圖片繪制的區域 Rectangle imgRect = new Rectangle(6, e.Bounds.Y + 3, 30, 30); e.Graphics.DrawImage(img, imgRect); //文本內容顯示區域 Rectangle textRect = new Rectangle(imgRect.Right + 2, imgRect.Y, e.Bounds.Width - imgRect.Width, e.Bounds.Height - 2); //獲得項文本內容,繪制文本 String itemText = Items[e.Index].ToString(); //文本格式垂直居中 StringFormat strFormat = new StringFormat(); strFormat.LineAlignment = StringAlignment.Center; e.Graphics.DrawString(itemText, new Font("微軟雅黑", 12), Brushes.Black, textRect, strFormat); base.OnDrawItem(e); } public class ItemEx { public ItemEx(string text, Image img) { Text = text; Image = img; } public string Text { get; set; } public Image Image { get; set; } public override string ToString() { return Text; } } } }
這樣就用Winform從技術上重新實現了前面的WPF+SQL Server 2008的TaskVision。
感受的是Winform datagridview和WPF datagrid的使用,區別,及兩種不同的界面驅動編碼方式。
關於:實現Winform自定義控件ImageComboBoxUserControl,也可以參考DebugLZQ前面的一篇博文:在Winform窗體中使用WPF控件(附源碼)
關於:DataGridView控件默認只支持DataGridViewButtonColumn、DataGridViewCheckBoxColumn、DataGridViewComboBoxColumn、DataGridViewImageColumn、DataGridViewLinkColumn和DataGridViewTextBoxColumn六種列類型,如果你想要在DataGridView的列中添加其它的子控件,則需要自己實現DataGridViewColumn和DataGridViewCell。可參考:C# WinForm下DataGridView單選按鈕列和支持三種選擇狀態的復選框列的實現
另外:直接在datagridview中編輯,批量更新。如下:
View Code
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Data.SqlClient; namespace TaskVision_V_1_WinForm { public partial class Form4 : Form { public Form4() { InitializeComponent(); } private DataTable dt = new DataTable(); private SqlDataAdapter sda = new SqlDataAdapter(); private Boolean isUpdate = false; private void Form4_Load(object sender, EventArgs e) { LoadData(); } private void LoadData() { dataGridView1.AutoGenerateColumns = false; SqlConnection conn = new SqlConnection(@"server=LocalHost;database=TaskVision;Trusted_Connection=SSPI"); SqlCommand cmd = new SqlCommand("select * from tb_TaskInfo ", conn); sda.SelectCommand = cmd; sda.Fill(dt); dataGridView1.DataSource = dt; } private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e) { isUpdate = true; } /// <summary> /// 直接在datagridview中進行批量修改 /// </summary> private void button1_Click(object sender, EventArgs e) { if (isUpdate) { try { SqlCommandBuilder SCB = new SqlCommandBuilder(sda); sda.Update(dt); isUpdate = false; } catch (System.Exception ex) { MessageBox.Show(ex.ToString()); return; } MessageBox.Show("更新成功! "); } else { MessageBox.Show("沒有更新內容! "); } } } }
