怎样让WinForms下DataGrid可以像ASP.NET下的DataGrid一样使用自定义的模板列
昨天被問到一個問題:怎么把WinForms里的DataGrid的綁定了數據庫bit字段的列默認顯示的CheckBox換成“男”和“女”,也就是說怎么樣像ASP.NET的模板列那樣可以自定義。(此處不考慮在SQL在用Case把數據結果轉換了)
由于,基本沒有搞過WinForms,所以這個問題弄了很久才搞掂,可能對于WinForms高手來說,這是一個很簡單的問題。(我搜了一下網頁,沒有找到直接的解決方案,問了一些搞過WinForms的朋友,也沒有直接的解決方案,所以把我的解決方案放在博客園首頁,DUDU如覺不適合,請移除。)解決這個問題的副作用就是對WinForms的機制有了一點了解。
最終實現效果:
開始的思路還是ASP.NET的思路,企圖用WinForms的DataGrid的事件來實現。試了ControlAdde,BindingComplated等事件,都沒有用,有些能拿到綁定時的控件,卻拿不到對應的數據。
后來有朋友啟發用CurrencyManager來實現,試了半天,能拿到數據,又拿不到對應的綁定生成的控件了。
暈,后來還是控件開發的思想,既然可以用DataGridTextBoxColumnStyle和DataGridBoolColumnStyle分別生成TextBox和CheckBox,為什么不可以自定義一個DataGridColumnStyle來實現自定義呢?
結果還真是可行的:
????class?DataGridCustomBoolColumnStyle?:?DataGridColumnStyle
????{
????????private?Label?_customLabel?=?new?Label();
????????private?bool?_isEditing?=?false;
????????public?DataGridCustomBoolColumnStyle()
????????{
????????????_customLabel.Visible?=?false;
????????????_customLabel.Click?+=new?EventHandler(_customLabel_Click);
????????}
????????protected?override?void?Abort(int?rowNum)
????????{
????????????_isEditing?=?false;
????????????Invalidate();
????????}
????????void?_customLabel_Click(object?sender,?EventArgs?e)
????????{
????????????Label?lbl?=?sender?as?Label;
????????????if?(lbl.Text?==?"男")
????????????????lbl.Text?=?"女";
????????????else
????????????????lbl.Text?=?"男";
????????????this._isEditing?=?true;
????????????base.ColumnStartedEditing(_customLabel);
????????}
????????protected?override?object?GetColumnValueAtRow(CurrencyManager?source,?int?rowNum)
????????{
????????????object?o?=?base.GetColumnValueAtRow(source,?rowNum);
????????????bool?value?=?true;
????????????if?(Convert.IsDBNull(o))
????????????????value?=?true;
????????????else
????????????{
????????????????value?=?(bool)o;
????????????}
????????????return?value;
????????}
????????protected?override?void?SetDataGridInColumn(DataGrid?value)
????????{
????????????base.SetDataGridInColumn(value);
????????????if?(_customLabel.Parent?!=?null)
????????????{
????????????????_customLabel.Parent.Controls.Remove(_customLabel);
????????????}
????????????if?(value?!=?null)
????????????{
????????????????value.Controls.Add(_customLabel);
????????????}
????????}
????????protected?override?bool?Commit(CurrencyManager?dataSource,?int?rowNum)
????????{
????????????_customLabel.Bounds?=?Rectangle.Empty;
????????????_customLabel.Visible?=?false;
????????????if?(!_isEditing)
????????????????return?true;
????????????_isEditing?=?false;
????????????try
????????????{
????????????????bool?value?=?(_customLabel.Text?==?"男");
????????????????SetColumnValueAtRow(dataSource,?rowNum,?value);
????????????}
????????????catch?(Exception)
????????????{
????????????????Abort(rowNum);
????????????????return?false;
????????????}
????????????Invalidate();
????????????return?true;
????????}
????????protected?override?void?Edit(CurrencyManager?source,?int?rowNum,?System.Drawing.Rectangle?bounds,?bool?readOnly,?string?displayText,?bool?cellIsVisible)
????????{
????????????bool?value?=?(bool)GetColumnValueAtRow(source,?rowNum);
????????????if?(cellIsVisible)
????????????{
????????????????_customLabel.Bounds?=?new?Rectangle(bounds.X?+?2,?bounds.Y?+?2,?bounds.Width?-?4,?bounds.Height?-?4);
????????????????_customLabel.Visible?=?true;
????????????}
????????????else
????????????{
????????????????_customLabel.Visible?=?false;
????????????}
????????????_customLabel.Text?=?value???"男"?:?"女";
????????????if?(_customLabel.Visible)
????????????{
????????????????DataGridTableStyle.DataGrid.Invalidate(bounds);
????????????}
????????????_customLabel.BackColor?=?Color.Red;
????????}
????????protected?override?int?GetMinimumHeight()
????????{
????????????return?_customLabel.PreferredHeight?+?4;
????????}
????????protected?override?int?GetPreferredHeight(System.Drawing.Graphics?g,?object?value)
????????{
????????????return?_customLabel.PreferredHeight?+?4;
????????}
????????protected?override?System.Drawing.Size?GetPreferredSize(System.Drawing.Graphics?g,?object?value)
????????{
????????????return?new?Size(40,?_customLabel.PreferredHeight?+?4);
????????}
????????protected?override?void?Paint(System.Drawing.Graphics?g,?System.Drawing.Rectangle?bounds,?CurrencyManager?source,?int?rowNum,?System.Drawing.Brush?backBrush,?System.Drawing.Brush?foreBrush,?bool?alignToRight)
????????{
????????????bool?value?=?(bool)GetColumnValueAtRow(source,?rowNum);
????????????g.FillRectangle(backBrush,?bounds);
????????????bounds.Offset(0,?2);
????????????bounds.Height?-=?2;
????????????g.DrawString(value???"男"?:?"女",?DataGridTableStyle.DataGrid.Font,?foreBrush,?bounds);
????????}
????????protected?override?void?Paint(Graphics?g,Rectangle?bounds,CurrencyManager?source,int?rowNum)
????????{
????????????Paint(g,?bounds,?source,?rowNum,?false);
????????}
????????protected?override?void?Paint(Graphics?g,?Rectangle?bounds,?CurrencyManager?source,int?rowNum,bool?alignToRight)
????????{
????????????Brush?coreBrush?=?_isEditing???Brushes.Red?:?Brushes.White;
????????????Brush?backBrush?=?_isEditing???Brushes.Blue?:?Brushes.Black;
????????????Paint(
????????????????g,?bounds,
????????????????source,
????????????????rowNum,
????????????????coreBrush,
????????????????backBrush,
????????????????alignToRight);
????????}
????}
?
//使用方法????????????DataGridTableStyle?dgts?=?new?DataGridTableStyle();
????????????dgts.MappingName?=?this.dataSet11.Employees.TableName;
????????????this.dataGrid1.TableStyles.Add(dgts);
????????????GridColumnStylesCollection?gcsc?=?dataGrid1.TableStyles[0].GridColumnStyles;
????????????DataGridBoolColumn?dgbc?=?gcsc[gcsc.Count?-?1]?as?DataGridBoolColumn;
????????????DataGridCustomBoolColumnStyle?dgcbc?=?new?DataGridCustomBoolColumnStyle();
????????????dgcbc.MappingName?=?dgbc.MappingName;
????????????gcsc.Remove(dgbc);
????????????gcsc.Add(dgcbc);
????????????this.employeesTableAdapter.Fill(this.dataSet11.Employees);
????????????this.dataGrid1.DataSource?=?this.dataSet11.Employees;
這個實現很簡單,數據與顯示之間的映射是固定的,既然簡單的能實現,我們再來實現個復雜的,用ComboBox來表示一些固定值的選擇,比如enum和bool,因為數據庫中的數據并沒有enum,所以,這個DataGridComboBoxColumnStyle提供兩個委托,可以數據到ComboBox項和ComboBox項到數據之間做一個處理
????public?delegate?string?FormatValueToString(object?value);
????public?delegate?object?ParseStringToValue(string?value);
????class?DataGridComboBoxColumnStyle:DataGridColumnStyle
????{
????????public?FormatValueToString?FormartDelegate;
????????public?ParseStringToValue?ParseDelegate;
????????private?bool?_isEditing?=?false;
????????private?ComboBox?_combo?=?new?ComboBox();
????????public?ComboBox?InnerComboBox
????????{
????????????get
????????????{
????????????????return?_combo;
????????????}
????????}
????????public?DataGridComboBoxColumnStyle()
????????{
????????????_combo.SelectedIndexChanged?+=?new?EventHandler(_combo_SelectedIndexChanged);
????????????_combo.Visible?=?false;
????????}
????????void?_combo_SelectedIndexChanged(object?sender,?EventArgs?e)
????????{
????????????this._isEditing?=?true;
????????????base.ColumnStartedEditing(_combo);
????????}
????????protected?override?void?Abort(int?rowNum)
????????{
????????????_isEditing?=?false;
????????????Invalidate();
????????}
????????protected?override?void?SetDataGridInColumn(DataGrid?value)
????????{
????????????base.SetDataGridInColumn(value);
????????????if?(_combo.Parent?!=?null)
????????????{
????????????????_combo.Parent.Controls.Remove(_combo);
????????????}
????????????if?(value?!=?null)
????????????{
????????????????value.Controls.Add(_combo);
????????????}
????????}
???????
????????protected?override?bool?Commit(CurrencyManager?dataSource,?int?rowNum)
????????{
????????????_combo.Bounds?=?Rectangle.Empty;
????????????_combo.Visible?=?false;
????????????if?(!_isEditing)
????????????????return?true;
????????????_isEditing?=?false;
????????????
????????????try
????????????{
????????????????string?value?=?_combo.SelectedText;
????????????????SetColumnValueAtRow(dataSource,?rowNum,?value);
????????????}
????????????catch?(Exception)
????????????{
????????????????Abort(rowNum);
????????????????return?false;
????????????}
????????????Invalidate();
????????????return?true;
????????}
????????protected?override?object?GetColumnValueAtRow(CurrencyManager?source,?int?rowNum)
????????{
????????????object?value?=?base.GetColumnValueAtRow(source,?rowNum);
????????????if?(Convert.IsDBNull(value))
????????????{
????????????????value?=?this.NullText;
????????????}
????????????if?(FormartDelegate?!=?null)
????????????{
????????????????value?=?FormartDelegate(value);
????????????}
????????????return?value;
????????}
????????protected?override?void?SetColumnValueAtRow(CurrencyManager?source,?int?rowNum,?object?value)
????????{
????????????if(ParseDelegate?!=?null)
????????????{
????????????????value?=?ParseDelegate((string)value);
????????????}
????????????base.SetColumnValueAtRow(source,?rowNum,?value);
????????}
????????protected?override?void?Edit(CurrencyManager?source,?int?rowNum,?System.Drawing.Rectangle?bounds,?bool?readOnly,?string?displayText,?bool?cellIsVisible)
????????{
????????????string?value?=?(string)GetColumnValueAtRow(source,?rowNum);
????????????if?(cellIsVisible)
????????????{
????????????????_combo.Bounds?=?new?Rectangle(bounds.X?+?2,?bounds.Y?+?2,?bounds.Width?-?4,?bounds.Height?-?4);
????????????????_combo.Visible?=?true;
????????????}
????????????else
????????????{
????????????????_combo.Visible?=?false;
????????????}
????????????for?(int?i?=?0;?i?<?_combo.Items.Count;?i++)
????????????{
????????????????if?(value?==?(string)_combo.Items[i])
????????????????{
????????????????????_combo.SelectedIndex?=?i;
????????????????????break;
????????????????}
????????????}
????????????if?(_combo.Visible)
????????????{
????????????????DataGridTableStyle.DataGrid.Invalidate(bounds);
????????????}
????????}
????????protected?override?int?GetMinimumHeight()
????????{
????????????return?_combo.PreferredHeight?+?4;
????????}
????????protected?override?int?GetPreferredHeight(System.Drawing.Graphics?g,?object?value)
????????{
????????????return?_combo.PreferredHeight?+?4;
????????}
????????protected?override?System.Drawing.Size?GetPreferredSize(System.Drawing.Graphics?g,?object?value)
????????{
????????????return?new?Size(100,?_combo.PreferredHeight?+?4);
????????}
????????protected?override?void?Paint(System.Drawing.Graphics?g,?System.Drawing.Rectangle?bounds,?CurrencyManager?source,?int?rowNum,?System.Drawing.Brush?backBrush,?System.Drawing.Brush?foreBrush,?bool?alignToRight)
????????{
????????????string?value?=?(string)GetColumnValueAtRow(source,?rowNum);
????????????g.FillRectangle(backBrush,?bounds);
????????????bounds.Offset(0,?2);
????????????bounds.Height?-=?2;
????????????g.DrawString(value,?DataGridTableStyle.DataGrid.Font,?foreBrush,?bounds);
????????}
????????protected?override?void?Paint(Graphics?g,Rectangle?bounds,CurrencyManager?source,int?rowNum)
????????{
????????????Paint(g,?bounds,?source,?rowNum,?false);
????????}
????????protected?override?void?Paint(Graphics?g,?Rectangle?bounds,?CurrencyManager?source,int?rowNum,bool?alignToRight)
????????{
????????????Brush?coreBrush?=?_isEditing???Brushes.Red?:?Brushes.White;
????????????Brush?backBrush?=?_isEditing???Brushes.Blue?:?Brushes.Black;
????????????Paint(
????????????????g,?bounds,
????????????????source,
????????????????rowNum,
????????????????coreBrush,
????????????????backBrush,
????????????????alignToRight);
????????????
????????}
????}
?
//使用方法????????????DataGridTableStyle?dgts?=?new?DataGridTableStyle();
????????????dgts.MappingName?=?this.dataSet11.Employees.TableName;
????????????this.dataGrid1.TableStyles.Add(dgts);
????????????GridColumnStylesCollection?gcsc?=?dataGrid1.TableStyles[0].GridColumnStyles;
????????????DataGridBoolColumn?dgbc?=?gcsc[gcsc.Count?-?1]?as?DataGridBoolColumn;
????????????DataGridComboBoxColumnStyle?dgcbc?=?new?DataGridComboBoxColumnStyle();
????????????dgcbc.MappingName?=?dgbc.MappingName;
????????????//這里定義ComboBOx的樣式和項,因為整個ComboBox都公開了,所以隨你怎么設置都行
????????????dgcbc.InnerComboBox.Items.Add("男");
????????????dgcbc.InnerComboBox.Items.Add("女");
????????????dgcbc.InnerComboBox.DropDownStyle?=?ComboBoxStyle.DropDownList;
????????????//這里定義數據和ComboBOx項之間如何轉換
????????????dgcbc.ParseDelegate?=?new?ParseStringToValue(ParseStringToBool);
????????????dgcbc.FormartDelegate?=?new?FormatValueToString(FormatBoolToString);
????????????gcsc.Remove(dgbc);
????????????gcsc.Add(dgcbc);
????????????this.employeesTableAdapter.Fill(this.dataSet11.Employees);
????????????this.dataGrid1.DataSource?=?this.dataSet11.Employees;
熟悉WinForms的設計思路之后,我們又可以像用ASP.NET的DataGird一樣用DataGrid了。
WinForms我是新手,請多指教。。。
總結
以上是生活随笔為你收集整理的怎样让WinForms下DataGrid可以像ASP.NET下的DataGrid一样使用自定义的模板列的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java已知一个二叉树_#二叉树复习#
- 下一篇: java设计模式 组合_JAVA 设计模