DataGrid skills
------- How to Shield Unit Input
Sometimes I listen to some friends complaining that .NET's DataGrid is not very easy. As far as my personal experience, DataGrid's function is very powerful, which can make us complete a variety of work, but unfortunately, it is not simple enough. I have accumulated some solutions to some problems that I often encountered, and now I summarize them for your reference.
One problem that often encounters is: We hope that a column of DataGrid can only enter a specific text, such as: You cannot enter a number. The following example shows how to implement this function. Create a Window application, join a DataGrid and SqlConnection, connect the SQL database Northwind.
namespace WindowsApplication1 {public class Form1: System.Windows.Forms.Form {private myDataGrid dataGrid1; private System.Data.SqlClient.SqlConnection sqlConnection1; // global variables added oldValue, which represents a cell with the original text. PRIVATE STRING OLDVALUE;
private void Form1_Load (object sender, System.EventArgs e) {oldValue = ""; SqlDataAdapter sda = new SqlDataAdapter ( "select LastName, FirstName from employees", this.sqlConnection1); DataSet ds = new DataSet (); sda.Fill ( ds, "employees"); DataGridTableStyle ats = new DataGridTableStyle (); ats.MappingName = "employees"; DataGridColorColumn dcs1 = new DataGridColorColumn (); dcs1.HeaderText = "lastname"; ats.GridColumnStyles.Add (dcs1); DataGridTextBoxColumn dcs2 = new DataGridTextBoxColumn (); dcs2.HeaderText = "firstname"; dcs2.MappingName = "FirstName"; dcs2.TextBox.TextChanged = new EventHandler (DataGridTextChanged); dcs2.TextBox.Enter = new EventHandler (DataGridTextBox_Enter); ats.GridColumnStyles. Add (DCS2); this.dataGrid1.tablestyles.add (ats); this.DataGrid1.datasource = DS; this.DataGrid1.datamember = "EMPLOYEES";
Text oldValue private void DataGridTextBox_Enter (object sender, EventArgs e) {// When a cell receives focus, the recording of the cell = ((DataGridTextBoxColumn) this.dataGrid1.TableStyles [0] .GridColumnStyles [1]). TextBox. Text;} private void DataGridTextChanged (object sender, EventArgs e) {int index = 0; string str = ((DataGridTextBoxColumn) this.dataGrid1.TableStyles [0] .GridColumnStyles [1]) TextBox.Text;. // when the cell When the text changes, check if there is an illegal character while (index ------------ How to implement multi-line head Sometimes I listen to some friends complaining that .NET's DataGrid is not very easy. As far as my personal experience, DataGrid's function is very powerful, which can make us complete a variety of work, but unfortunately, it is not simple enough. I have accumulated some solutions to some problems that I often encountered, and now I summarize them for your reference. One problem that is often encountered is: We hope that the header of DataGrid is multi-line (Figure 1). I have been looking for a solution for a long time I haven't found a solution, and later I thought of the CAPTIONTEXT and CAPTIONFONT attributes of DataGrid. So I would like to draw multiple lines of heads in the display area of CAPTION. The following sample code implements this idea, as shown in Figure 1. First, you need to write a class to represent the sheet of self-drawn, this class records the display text, icon, and the information belonging to the columns it juropteed. // Header class public class TopHeaderColumn {public TopHeaderColumn () {this.columnCollection = new ArrayList ();} private string caption; // text header public string Caption {get {return caption;} set {caption = value ;}} private ArrayList columnCollection; // record information pertaining to the columns of the header jurisdiction (the collection by adding to the object) public ArrayList ColumnCollection {get {return this.columnCollection;} set {this.columnCollection = value;} } Private int width; // Width of the header PUBLIC INT WIDTH {GET {Return Width;} set {width = value;}} private image image = null; // Metet Icon PUBLIC Image Image;} set {image = value;}} } In addition, because the next code requires the location of the DataGrid horizontal scroll bar, and the DataGrid cannot obtain the position of the horizontal scroll bar, so you need to make a little modification to the DataGrid. Public Class MyDataGrid: DataGrid {public scrollbar hscrollbar {get {return this.hizscrollbar;}}} Ok, you can work. Create a new Window application, join a MyDataGrid, SqlConnection, and ImageList, connect the SQL database Northwind. Of course, we have added the above code namespace WindowsApplication1 {public class Form1: System.Windows.Forms.Form {private System.Data.SqlClient.SqlConnection sqlConnection1; private myDataGrid dataGrid1; private ArrayList al; private System.Windows.Forms.ImageList imageList1 // Join this sentence in InitializeComponent (): this.dataGrid1 = new mydataGrid (), and sets other DataGrid properties according to your needs. Note that CaptionVisible must be set to true, captionText = "" ". private void Form1_Load (object sender, System.EventArgs e) {SqlDataAdapter da = new SqlDataAdapter ( "select lastname, firstname, Address, City from employees", this.sqlConnection1); DataSet ds = new DataSet (); da.Fill (ds , "Employees"); this.dataGrid1.datasource = DS; this.DataGrid1.datamember = "EMPLOYEES"; // columns in the DataGrid DataGridTextBoxColumn c1 = new DataGridTextBoxColumn (); DataGridTextBoxColumn c2 = new DataGridTextBoxColumn (); DataGridTextBoxColumn c3 = new DataGridTextBoxColumn (); DataGridTextBoxColumn c4 = new DataGridTextBoxColumn (); c1.MappingName = "lastname"; c2.MappingName = "firstname"; c3.mappingname = "address"; c4.mappingname = "city"; c1.Headertext = "lastname"; c2.Headertext = "firstname"; c3.Headertext = "address; c4.Headertext =" City "; c1.widthchanged = new eventHandler (this.abc); // The width change adjusts the header width c2.widthchanged = new eventhandler (this.abc); c3.widthchanged = new eventhandler (this.abc);c4.WidthChanged = new EventHandler (this.abc); DataGridTableStyle dts = new DataGridTableStyle (); dts.GridColumnStyles.Add (c1); dts.GridColumnStyles.Add (c2); dts.GridColumnStyles.Add (c3); dts.GridColumnStyles .Add (c4); DTS.MAppingName = "EMPLOYEES"; this.dataGrid1.tablestyles.add (dts); // Establish a self-drawn head class and add them to the collection al al = new arraylist (); topheaderColumn tc1 = new TopHeaderColumn (); tc1.caption = "name"; tc1.image = this.imagelist1.images [0]; Tc1.columncollection.Add (0); // Record the index tc1.columncollection.add (1) of the column it jurisdiction; tc1.width = c1.width c2.width; TopHeaderColumn TC2 = New TopHeaderColumn (); tc2.caption = "Address"; tc2.columncollection.Add (2); tc2.columncollection.Add (3); tc2.width = c3.width c4.width; al. ADD (TC1); Al.Add (TC2); this .DataGrid1.paint = new system.windows.Forms.PainteventHandler (this.DataGrid1_paint);} Private void DataGrid1_paint (Object Sender, System.Windows.Forms. Painteventargs E) {INT x = 0; // Calculate the left distance of the first header INT LEFT = this.dataGrid1.tablestyles [0]. RowHeaderwidth-this. DataGrid1.hscrollBar.Value; // Traversing the head collection Al, draws the header Foreach (Object O in this.al) {// calculates the left distance of the header (text center) x = left ((TopHeaderColumn) o) .Width-convert.Toint32 (E.Graphics. MeasureString ((TopHeaderColumn) o) .caption, this.dataGrid1.captionFont). Width)) / 2; // Complete the header Draw IF ((TopHeaderColumn) O ) .Image! = Null) E.Graphics.drawImage ((TopHeaderColumn) o) .image, x-imagelist1.images [0] .size.width, 0); E.Graphics.drawstring ((TopHeaderColumn) O) .Caption, this.dataGrid1. CaptionFont, New Solidbrush (THISDATAGRID1.CAPTIONFORECOLOR), X, 0); IF (x> 0) E.Graphics.drawline (New Pen (Color.Black, 2), Left-1, 0, Left-1, this.DataGrid1.Height; // Calculate the left distance of the next header Left = ((TopHeaderColumn) o) .width;} if (x Private Void ABC (Object Sender, Eventargs E) {// Sets the width of the header foreach (Object O in this.al) {(TopHeaderColumn) o) .width = 0; Foreach (INT I in (TopHeaderColumn) O) .ColumnCollection) {((TopHeaderColumn) o) .Width = this.dataGrid1.TableStyles [0] .GridColumnStyles [i] .Width;}}} private void dataGrid1_Scroll (object sender, System.EventArgs e) {this.dataGrid1.Refresh (); The above code implements two-layer header, as for the three-layer header. About how to implement a DataGrid multi-layer header, many netizens mentioned that there is no particularly convenient way. -------- How to implement a drop-down list Sometimes I listen to some friends complaining that .NET's DataGrid is not very easy. As far as my personal experience, DataGrid's function is very powerful, which can make us complete a variety of work, but unfortunately, it is not simple enough. I have accumulated some solutions to some problems that I often encountered, and now I summarize them for your reference. One problem that often encounters is: We want to have such a drop-down list when editing cell content, as shown in Figure 1: figure 1 Idea: 1 Write a class ComboForm to represent the drop-down list, the class contains two members: Form form and DataGrid components. 2 Write a class NokeyupComboBox (inherited ComboBox), the purpose is to block the WM_KEYUP message to avoid problems when pressing the Tab. 3 Write a class inherited in DataGridTextBoxColumn, named DataGridComboFormColumn. Add a ComboBox and a COMBOFORM in the class, the class implementation below: A Edit the cell content when the cell content is displayed, and the drop-down time display the drop-down list ComboForm; c Mouse Click the drop-down list, hide the Comboform and select the user. The content written in the unit (of course, you can also set up additional hidden drop-down list, such as pressing the Enter key); D drop-down list ComboForm hides when there is no focus. Code: // comboForm class: public class comboForm: Form {private DataGrid dataGrid; public DataGrid DataGrid {get {return dataGrid;} set {dataGrid = value;}} public comboForm () {this.FormBorderStyle = FormBorderStyle.None; this. StartPosition = FormStartPosition.Manual; dataGrid = new dataGrid (); this.Controls.Add (dataGrid); dataGrid.Dock = DockStyle.Fill; dataGrid.CaptionVisible = false;}} // NoKeyUpComboBox class: public class NoKeyUpComboBox: ComboBox {const INT WM_KEYUP = 0x101; protected override void WndProc (REF MSSAGE MSG) {if (msg.msg == WM_KEYUP) Return; Base.WndProc (Ref Msg);}} // DataGridComboFormColumn class: public class DataGridComboFormColumn: DataGridTextBoxColumn {private NoKeyUpComboBox comboBox; private CurrencyManager _source; private int rowNum; private comboForm frm; public comboForm Frm {get {return frm;}} // we will use the attribute Index represents the cell content content of index column drop-down list associated private int index; public int index {get {return index;} set {index = value;}} public DataGridComboFormColumn () {frm = new comboForm (); comboBox = new NoKeyUpComboBox () ; frm.Deactivate = new EventHandler (frm_deactive); frm.DataGrid.Click = new EventHandler (grid_click); this.comboBox.DropDown = new EventHandler (comboBox_dropDown); this.comboBox.Leave = new EventHandler (comboBox_leave);} // hide private void frm_deactive (object sender, EventArgs e) {frm.Hide when the drop-down list // --Frm does not have focus; hide private void comboBox_leave (object sender, EventArgs e) {comboBox.Visible = false} does not have focus when comboBox (); ComboBox.visible = false;} // ComboBox cleales the drop-down list - FRM Private Void ComboBox_Dropdown (Object Sender, Eventa RGS E) {// Here you can also define the location of the drop-down list by the length of the drop-down list, frm.left = ComboBox.PointToscreen (NEW POINT (0, ComboBox.Height)). x; frm.top = ComboBox.PointToscreen (New Point (0, ComboBox.Height)). Y; fm.show (); frm.bringtofront ();} // When you click the DataGrid of the drop-down list, the selected content is written into the unit and hide dropdown --Frm private void grid_click (object sender, EventArgs e) {BindingManagerBase cm = frm.BindingContext [Frm.DataGrid.DataSource, frm.DataGrid.DataMember]; comboBox.Text = ((DataRowView) cm.Current) [index ] .Tostring (); this.textBox.text = (DATAROWVIEW) cm.current [index] .tostring (); frm.hide (); comboBox.visible = false; this.setColumnValueatrow (_Source, rownum, this. TEXTBOX.TEXT);} // Overload Edit method, Instead of using comboBox TextBox protected override void Edit (CurrencyManager dataSource, int rowNum, Rectangle bounds, bool readOnly, string instanttext, bool cellVisible) {base.Edit (dataSource, rowNum, bounds, readOnly, instanttext, cellVisible); comboBox.Parent = this .TextBox.Parent; ComboBox.LEFT = this.textBox.Left-2; ComboBox.top = this.textBox.top-2; ComboBox.Size = new size (this.TextBox.width, this.comboBox.Height); ComboBox .Text = this.textbox.text; this.textbox.visible = false; combobox.visible = true; comboBOX.BRINGTOFRONT (); comboBox.focus (); _Source = dataource;} = rownum;}} The following example shows how to use the DataGridComboFrom class: New Windows application, join SQLConnection, join the SQL database Northwind, join the following code. private void Form1_Load (object sender, System.EventArgs e) {SqlDataAdapter da = new SqlDataAdapter ( "select ProductName from Products", this.sqlConnection1); DataSet ds = new DataSet (); da.Fill (ds, "products"); DataSet DS_COMBO = New DataSet (); da.selectcommand = New SqlCommand ("Select ProductName, QuantityPerunit, Unitprice from Products", this.sqlConnection1); Da.Fill (DS_COMBO, "Products"); DataGridTableStyle dts = new DataGridTableStyle (); dts.MappingName = "products"; myDataGridColumn col = new myDataGridColumn (); col.MappingName = "ProductName"; col.Width = 100; col.Index = 0; col.HeaderText = "ProductName " Col.frm.dataGrid.datasource = DS_COMBO; // Set Data Source of the drop-down list col.frm.dataGrid.DataMember = "Products"; dts.gridColumnStyles.add (color); this.dataGrid1.tablestyles.add (dts); This.DataGrid1.SetDataBinding (DS, "Products"); ------------ How to display data from different DataTable in DataGrid sometimes listening to some friends complaining that .NET's DataGrid is not very easy to use. As far as my personal experience, DataGrid's function is very powerful, which can make us complete a variety of work, but unfortunately, it is not simple enough. I have accumulated some solutions to some problems that I often encountered, and now I summarize them for your reference. One of the frequently encountered problems is: How to display the field combination from different DATATABLE in DataGrid? Of course, data can be merged into a DataTable, but sometimes due to other restrictions cannot be merged, the following provides a method of displaying data from different DataTable (in a DataSet) in the DataGrid. Data in DataSet We hope that the data is displayed in DataGrid as shown below. Here are an example of how to implement how to display data from different DataTable in the DataGrid. Basic ideas: Obviously, DataGrid can't bind two DataTable at the same time, then make it display two DataTable data, only in DataGridColumn. Take the above structure as an example, we build a class DataGridJointboxColumn inherited DataGridTextBoxColumn, overloading the getColumnValueatrow method. The functionality to be implemented is: Data Source is DataTable1, the return value is DataTable2.lastname or DataTable2.Firstname corresponding to DataTable1.employeeid. DataTable1.employeeID is 1-to-many contacts, and we can add this contact to the DataSet, you can get the value of DataTable1.lastName and DataTable2.FirstName corresponding to DataTable1.Employeeid by getParenTrow method. The specific code is as follows: public class JoinTextBoxColumn: DataGridTextBoxColumn {string relation; // 1 represents DataTable1.EmployeeID DataTable2.EmployeeID with multi-contact DataColumn col; // return DataTable2 column indicates public JoinTextBoxColumn (string relation, DataColumn col) {this.relation = relation; this.col = col; base.ReadOnly = true;} protected override object GetColumnValueAtRow (CurrencyManager cm, int RowNum) {try {DataRow dr = ((DataView) cm.List) [RowNum] .Row; DataRow parentdr = dr.GetParentRow (RELATION); RETURN PARENTDR [COL]; // Return value is the lastname or firstname} catch {return "" corresponding to DATATABLE1.Employeeid, ""; // Avoid eventual (CurrencyManager CM) when adding new rows}} protected override bool INT rownum) {return false;} public new bo}}}} The following code shows how to use class DataGridjoin COLUMN. Create a Windows program, join a DataGrid and a SQLCONNECTION, connect the database Northwind. Add the following code in Form_Load: private void Form1_Load (object sender, System.EventArgs e) {SqlDataAdapter sda1 = new SqlDataAdapter ( "select EmployeeID, LastName, FirstName from Employees", this.sqlConn); SqlDataAdapter sda3 = new SqlDataAdapter ( "select OrderID, EmployeeID, OrderDate, RequiredDate From Orders ", this.sqlconn; DS = new dataset (); SDA1.FILL (DS, "EMP"); SDA3.FILL (DS, "ORD"); DS.RELATIONS.ADD ("ORD_EMP", DS.TABLES ["EMP"]. Column ["EmployeeID"], DS.Tables ["ORD"]. Column ["EmployeeID"]); ds.tables ["ORD" ] .Columns.Add ( "lastName", typeof (string));. ds.Tables [ "ord"] Columns.Add ( "firstName", typeof (string)); DataGridTableStyle dt = new DataGridTableStyle (); DataGridColumnStyle dc; dc = new DataGridTextBoxColumn (); dc.MappingName = "OrderID"; dc.HeaderText = "OrderID"; dt.GridColumnStyles.Add (dc); dc = new DataGridTextBoxColumn (); dc.MappingName = "EmployeeID"; dc.HeaderText = "EmployeeID"; DT.GridColumnStyles.Add (DC); dc = new JoinTextBoxColumn ( "ord_emp", ds.Tables [ "emp"] Columns [ "firstName"].); dc.MappingName = "firstName"; dc.HeaderText = "firstName"; dt.GridColumnStyles.Add (dc) ; DC = New JointextBoxColumn ("ORD_EMP", DS.Tables ["EMP"]. Column ["Lastname"]); dc.mappingname = "lastname"; dc.headertext = "LastName"; DT.GridColumnStyles.Add (DC) ; DC = New DataGridTextBoxColumn (); dc.mappingname = "ORDERDATE"; DC.Headertext = "ORDERDATE"; DT.GRIDCOLUMNSTYLES.ADD (DC); DC = New DataGridTextBoxColumn (); dc.mappingname = "requireddate"; dc.headertext = "RequiredDate"; DT.GridColumnStyles.Add (DC); Dt.mappingName = "ORD"; this.DataGrid1.tableStyles.Add (DT); This.DataGrid1.datasource = DS; this.DataGrid1.datamember = "ORD";