We use cookies to give you the best experience on our website. If you continue to browse, then you agree to our privacy policy and cookie policy. Image for the cookie policy date

GridGroupingControl: Delete row

Hello. How to implement "Delete" button not only for top-level table row, but for child rows too. Thanks. Current code: private void button2_Click(object sender, System.EventArgs e) { Record r = this.gridGroupingControl1.Table.CurrentRecord; if(r != null) { r.Delete(); } }

5 Replies

SA Satish July 6, 2004 06:22 AM UTC

Here is the code... using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using Syncfusion.Windows.Forms.Grid; namespace UpdateableExpandGrid { /// /// Summary description for Form1. /// public class Form1 : System.Windows.Forms.Form { private GridDataBoundGrid gridDataBoundGrid1; private System.Windows.Forms.Button buttonExpandAll; private System.Windows.Forms.Button buttonCollapseAll; private System.Windows.Forms.Button buttonChangeValue; private System.Windows.Forms.Button buttonDeleteRow; private System.Windows.Forms.Button buttonInsertRow; /// /// Required designer variable. /// private System.ComponentModel.Container components = null; public Form1() { // // Required for Windows Form Designer support // InitializeComponent(); // // TODO: Add any constructor code after InitializeComponent call // } /// /// Clean up any resources being used. /// protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Windows Form Designer generated code /// /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// private void InitializeComponent() { this.gridDataBoundGrid1 = new Syncfusion.Windows.Forms.Grid.GridDataBoundGrid(); this.buttonExpandAll = new System.Windows.Forms.Button(); this.buttonCollapseAll = new System.Windows.Forms.Button(); this.buttonChangeValue = new System.Windows.Forms.Button(); this.buttonDeleteRow = new System.Windows.Forms.Button(); this.buttonInsertRow = new System.Windows.Forms.Button(); ((System.ComponentModel.ISupportInitialize)(this.gridDataBoundGrid1)).BeginInit(); this.SuspendLayout(); // // gridDataBoundGrid1 // this.gridDataBoundGrid1.AllowDragSelectedCols = true; this.gridDataBoundGrid1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right); this.gridDataBoundGrid1.Location = new System.Drawing.Point(16, 56); this.gridDataBoundGrid1.Name = "gridDataBoundGrid1"; this.gridDataBoundGrid1.ShowCurrentCellBorderBehavior = Syncfusion.Windows.Forms.Grid.GridShowCurrentCellBorder.GrayWhenLostFocus; this.gridDataBoundGrid1.Size = new System.Drawing.Size(520, 288); this.gridDataBoundGrid1.SortBehavior = Syncfusion.Windows.Forms.Grid.GridSortBehavior.DoubleClick; this.gridDataBoundGrid1.TabIndex = 0; this.gridDataBoundGrid1.Text = "gridDataBoundGrid1"; // // buttonExpandAll // this.buttonExpandAll.Location = new System.Drawing.Point(16, 16); this.buttonExpandAll.Name = "buttonExpandAll"; this.buttonExpandAll.TabIndex = 1; this.buttonExpandAll.Text = "ExpandAll"; this.buttonExpandAll.Click += new System.EventHandler(this.buttonExpandAll_Click); // // buttonCollapseAll // this.buttonCollapseAll.Location = new System.Drawing.Point(88, 16); this.buttonCollapseAll.Name = "buttonCollapseAll"; this.buttonCollapseAll.TabIndex = 2; this.buttonCollapseAll.Text = "CollapseAll"; this.buttonCollapseAll.Click += new System.EventHandler(this.buttonCollapseAll_Click); // // buttonChangeValue // this.buttonChangeValue.Location = new System.Drawing.Point(160, 16); this.buttonChangeValue.Name = "buttonChangeValue"; this.buttonChangeValue.Size = new System.Drawing.Size(152, 23); this.buttonChangeValue.TabIndex = 3; this.buttonChangeValue.Text = "ChangeValueInCurrentRow"; this.buttonChangeValue.Click += new System.EventHandler(this.buttonChangeValue_Click); // // buttonDeleteRow // this.buttonDeleteRow.Location = new System.Drawing.Point(312, 16); this.buttonDeleteRow.Name = "buttonDeleteRow"; this.buttonDeleteRow.Size = new System.Drawing.Size(112, 23); this.buttonDeleteRow.TabIndex = 4; this.buttonDeleteRow.Text = "DeleteCurrentRow"; this.buttonDeleteRow.Click += new System.EventHandler(this.buttonDeleteRow_Click); // // buttonInsertRow // this.buttonInsertRow.Location = new System.Drawing.Point(424, 16); this.buttonInsertRow.Name = "buttonInsertRow"; this.buttonInsertRow.Size = new System.Drawing.Size(112, 23); this.buttonInsertRow.TabIndex = 5; this.buttonInsertRow.Text = "InsertAtCurrentRow"; this.buttonInsertRow.Click += new System.EventHandler(this.buttonInsertRow_Click); // // Form1 // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(552, 358); this.Controls.AddRange(new System.Windows.Forms.Control[] { this.buttonInsertRow, this.buttonDeleteRow, this.buttonChangeValue, this.buttonCollapseAll, this.buttonExpandAll, this.gridDataBoundGrid1}); this.Name = "Form1"; this.Text = "Form1"; this.Load += new System.EventHandler(this.Form1_Load); ((System.ComponentModel.ISupportInitialize)(this.gridDataBoundGrid1)).EndInit(); this.ResumeLayout(false); } #endregion /// /// The main entry point for the application. /// [STAThread] static void Main() { Application.Run(new Form1()); } private DataSet dSet; GridHierarchyLevel hlParentToChild; GridHierarchyLevel hlChildToGrandChild; GridHierarchyLevel hlParent; private void Form1_Load(object sender, System.EventArgs e) { //dataset ============================================== dSet = new DataSet(); DataTable parentTable = GetParentTable(); DataTable childTable = GetChildTable(); DataTable grandChildTable = GetGrandChildTable(); dSet.Tables.AddRange(new DataTable[]{parentTable, childTable, grandChildTable}); //setup the relations ======================================== DataColumn parentColumn = parentTable.Columns["parentID"]; DataColumn childColumn = childTable.Columns["ParentID"]; dSet.Relations.Add("ParentToChild", parentColumn, childColumn); parentColumn = childTable.Columns["childID"]; childColumn = grandChildTable.Columns["ChildID"]; dSet.Relations.Add("ChildToGrandChild", parentColumn, childColumn); //expand grid =================================================== this.gridDataBoundGrid1.DataSource = parentTable; hlParentToChild = this.gridDataBoundGrid1.Binder.AddRelation("ParentToChild"); hlChildToGrandChild = this.gridDataBoundGrid1.Binder.AddRelation("ChildToGrandChild"); hlParent = this.gridDataBoundGrid1.Binder.RootHierarchyLevel; //hlParentToChild.ShowHeaders = false; //hlChildToGrandChild.ShowHeaders = false; //hlParent.ShowHeaders = false; //setup the parentgridlayout hlParent.LayoutColumns(new string[]{"parentID", "ParentName", " ", " "}); this.gridDataBoundGrid1.Model.CoveredRanges.Add(GridRangeInfo.Cells(0, 4, 0, 5)); //gray the last 2 columns GridStyleInfo style = hlParent.InternalColumns[2].StyleInfo; style.Borders.All = new GridBorder(GridBorderStyle.None); style.BackColor = SystemColors.Control; style.CellType = "Static"; style.Enabled = false; style = hlParent.InternalColumns[3].StyleInfo; style.Borders.All = new GridBorder(GridBorderStyle.None); style.BackColor = SystemColors.Control; style.CellType = "Static"; style.Enabled = false; hlParent.RowStyle.BackColor = Color.PaleGoldenrod; //setup the child gridlayout hlParentToChild.LayoutColumns(new string[]{"childID", "Name", "ParentID", " "}); //gray the last column style = hlParentToChild.InternalColumns[3].StyleInfo; style.Borders.All = new GridBorder(GridBorderStyle.None); style.BackColor = SystemColors.Control; style.CellType = "Static"; style.Enabled = false; hlParentToChild.RowStyle.BackColor = Color.LightGoldenrodYellow; this.gridDataBoundGrid1.AllowResizeToFit = false; this.gridDataBoundGrid1.Model.ColWidths.ResizeToFit(GridRangeInfo.Rows(0, 2), GridResizeToFitOptions.IncludeHeaders); this.gridDataBoundGrid1.Model.ColWidths[1] = 20; this.gridDataBoundGrid1.Model.ColWidths[3] = 120; //handle Row expanding/collapse to hook bindlinglist.ListChanged event // for the child tables this.gridDataBoundGrid1.RowCollapsing += new GridRowEventHandler(grid_RowCollapsing); this.gridDataBoundGrid1.RowExpanded += new GridRowEventHandler(grid_RowExpanded); //handle to listen to teh changed event for the parent table CurrencyManager cm = (CurrencyManager)this.BindingContext[this.gridDataBoundGrid1.DataSource, this.gridDataBoundGrid1.DataMember]; ((IBindingList)cm.List).ListChanged += new ListChangedEventHandler(list_ListChanged); } #region Dynamically hooking and unhooking ListChanged event //ParentNodesOfExpandedNodes holds a list of parent nodes: key - parent nodes value- arraylist of ChildLists // used when a parent node is close so all children listchanged event handlers can be unhooked private Hashtable ParentNodesOfExpandedNodes = new Hashtable(); //hook the ListChange event for the node that opened //and save its parent node in the ParentNodesOfExpandedNodes hashtable private void grid_RowExpanded(object sender, GridRowEventArgs e) { GridBoundRecordState state = gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(e.RowIndex); if(state.ChildList != null) { ((IBindingList)state.ChildList).ListChanged += new ListChangedEventHandler(list_ListChanged); Console.WriteLine(" HOOKED " + e.RowIndex.ToString()); if(state.Parent != null) { SaveParentNode(state); } } } //help method that save the parent node of an expanded child // so, later if you close teh paerent, the child''s listchanged event can also be unhooked private void SaveParentNode(GridBoundRecordState state) { if(ParentNodesOfExpandedNodes.ContainsKey(state.Parent)) { ArrayList al = (ArrayList)ParentNodesOfExpandedNodes[state.Parent]; al.Add(state.ChildList); } else { ArrayList al = new ArrayList(); al.Add(state.ChildList); ParentNodesOfExpandedNodes.Add(state.Parent, al); } } //here we unhook the ListChnaged event for teh node this closing //as well as any child ListChanged event that is hooked private void grid_RowCollapsing(object sender, GridRowEventArgs e) { ResetNodeAndChildNodesAtRow(e.RowIndex); } //helper method that unhooks teh ListChanged event of teh row plus as well // as the listchanged events of any children node. Uses the ParentNodesOfExpandedNodes hahtable // to get at the children private void ResetNodeAndChildNodesAtRow(int row) { GridBoundRecordState state = gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(row); if(state.ChildList != null) { ((IBindingList)state.ChildList).ListChanged -= new ListChangedEventHandler(list_ListChanged); Console.WriteLine("UNHOOKED " + row.ToString()); } if(ParentNodesOfExpandedNodes.ContainsKey(state)) { ArrayList al = (ArrayList)ParentNodesOfExpandedNodes[state]; foreach(IBindingList list in al) { list.ListChanged -= new ListChangedEventHandler(list_ListChanged); Console.WriteLine("UNHOOKEDc " + row.ToString()); } ParentNodesOfExpandedNodes.Remove(state); } } #endregion #region ListChanged event handler that reacts to child changes private void list_ListChanged(object sender, ListChangedEventArgs e) { IBindingList list = (IBindingList) sender; if(list != null) { //find the parent row... int parentRow = findParentRowFromChildList(list); if(parentRow == -1) { //we have a parent row. Check for change. if(e.ListChangedType == ListChangedType.ItemChanged) { UpdateThisParentRow(e.NewIndex); } else if(e.ListChangedType == ListChangedType.ItemAdded || e.ListChangedType == ListChangedType.ItemDeleted) { UpdateThisParentRow(e.NewIndex); this.gridDataBoundGrid1.Refresh(); } return; } //recurs = 0; int screenRow = parentRow + e.NewIndex + 1;// - this.gridDataBoundGrid1.TopRowIndex - 1; for(int j = 1; j <= e.NewIndex; ++j) screenRow += ScreenRowsInChildren(parentRow + j); Console.WriteLine("Item#=" + e.NewIndex.ToString() + " parentRow: " + parentRow.ToString() + " screenRow: " + screenRow.ToString()); switch(e.ListChangedType) { case ListChangedType.ItemChanged: //just redraw screen row to show the change this.gridDataBoundGrid1.RefreshRange(GridRangeInfo.Row(screenRow)); Console.WriteLine("ItemChanged"); break; case ListChangedType.ItemAdded: //this opens & closes the parent node RefreshRow(parentRow); //put the currentcell somewhere this.gridDataBoundGrid1.Focus(); this.gridDataBoundGrid1.CurrentCell.Activate(screenRow - 1, 2); //minus 1 because of new row Console.WriteLine("ItemAdded"); break; case ListChangedType.ItemDeleted: //this opens & closes the parent node RefreshRow(parentRow); //put the currentcell somewhere this.gridDataBoundGrid1.Focus(); this.gridDataBoundGrid1.CurrentCell.Activate(screenRow, 2); //minus 1 because of new row Console.WriteLine("ItemDeleted"); break; default: break; } } } #endregion #region Button clicks private void buttonExpandAll_Click(object sender, System.EventArgs e) { this.gridDataBoundGrid1.ExpandAll(); } private void buttonCollapseAll_Click(object sender, System.EventArgs e) { this.gridDataBoundGrid1.CollapseAll(); } private void buttonChangeValue_Click(object sender, System.EventArgs e) { GridCurrentCell cc = this.gridDataBoundGrid1.CurrentCell; //change a value in the underlying datasource somehow //here we know the object is a datarowview GridBoundRecordState rs = this.gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(cc.RowIndex); object o = rs.ListManager.Current; DataRowView drv = (DataRowView) o; DataRow dr = drv.Row; dr[1] = "Changed.."; drv.EndEdit(); } private void buttonDeleteRow_Click(object sender, System.EventArgs e) { DataTable dt = this.dSet.Tables[0]; GridCurrentCell cc = this.gridDataBoundGrid1.CurrentCell; int row = cc.RowIndex; int col = cc.ColIndex; GridBoundRecordState rs = this.gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(cc.RowIndex); //remove the current record int i = rs.ListManager.Position; rs.ListManager.Position = i - 1; rs.ListManager.RemoveAt(i); RefreshCurrentParentNode(rs.ListManager.Position - 1); if(row >= this.gridDataBoundGrid1.Model.RowCount) row = row - 1; this.gridDataBoundGrid1.CurrentCell.MoveTo(row, col); } private void buttonInsertRow_Click(object sender, System.EventArgs e) { GridCurrentCell cc = this.gridDataBoundGrid1.CurrentCell; GridBoundRecordState rs = this.gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(cc.RowIndex); //add a new record to the same level object o = rs.ListManager.Current; DataRowView drv = (DataRowView) o; DataRow dr = drv.Row; DataTable dt = this.dSet.Tables[rs.LevelIndex]; //get the table DataRow newRow = dt.NewRow(); object[] values = null; switch(rs.LevelIndex) { case 0: this.numberOfParents += 1; //pkValue = this.numberOfParents; values = new object[]{this.numberOfParents, string.Format("parentName{0}", this.numberOfParents)}; break; case 1: this.numberOfChildren += 1; //pkValue = this.numberOfChildren; values = new object[]{this.numberOfChildren, string.Format("ChildName{0}",this.numberOfChildren), dr[2]}; break; case 2: this.numberOfGrandChildren += 1; //pkValue = this.numberOfGrandChildren; values = new object[]{this.numberOfGrandChildren, string.Format("GrandChildName{0}",numberOfGrandChildren), dr[2], dr[3]}; break; default: throw new IndexOutOfRangeException("Improper index"); } newRow.ItemArray = values; dt.Rows.Add(newRow); RefreshCurrentParentNode(dt.Rows.Count); } #endregion #region helper methods //refreshes the row form the tableIndex position private void UpdateThisParentRow(int tableIndex) { for(int row = this.gridDataBoundGrid1.Model.Rows.HeaderCount + 1; row <= this.gridDataBoundGrid1.ViewLayout.LastVisibleRow; ++row) { if(this.gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(row).LevelIndex == 0) { if(tableIndex == 0) { this.gridDataBoundGrid1.RefreshRange(GridRangeInfo.Row(row)); this.gridDataBoundGrid1.Model.ResetVolatileData(); return; } tableIndex--; } } } private void RefreshCurrentParentNode(int position) { //if the new row should be visible, then open & close its parent to rebind it... GridCurrentCell cc = this.gridDataBoundGrid1.CurrentCell; //change a value in the underlying datasource somehow //here we know the object is a datarowview GridBoundRecordState rs = this.gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(cc.RowIndex); if(rs.LevelIndex == 0) { int r = Math.Max(0, this.gridDataBoundGrid1.Binder.PositionToRowIndex(position)); gridDataBoundGrid1.CurrentCell.MoveTo(r, 1); gridDataBoundGrid1.RefreshRange(GridRangeInfo.Table()); return; } int parentLevel = rs.LevelIndex - 1; int row = cc.RowIndex - 1; while (row > this.gridDataBoundGrid1.Model.Rows.HeaderCount) { rs = this.gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(row); if(rs.LevelIndex == parentLevel) break; row -= 1; } if(row > this.gridDataBoundGrid1.Model.Rows.HeaderCount) { this.gridDataBoundGrid1.Model.BeginUpdate(); this.gridDataBoundGrid1.CollapseAtRowIndex(row); this.gridDataBoundGrid1.ExpandAtRowIndex(row); this.gridDataBoundGrid1.CollapseAtRowIndex(row); this.gridDataBoundGrid1.ExpandAtRowIndex(row); this.gridDataBoundGrid1.Model.EndUpdate(); } } // locates the parent row for a given childlist private int findParentRowFromChildList(IBindingList list) { int parentRow = -1; if(list != null) { //it looks first from the current row up for(int i = this.gridDataBoundGrid1.CurrentCell.RowIndex; i > this.gridDataBoundGrid1.Model.Rows.HeaderCount; --i) { if(this.gridDataBoundGrid1.IsExpandedAtRowIndex(i) && list == gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(i).ChildList) { parentRow = i; break; } } //if it doesn''t find it, it looks in teh second half if(parentRow == -1) { for(int i = this.gridDataBoundGrid1.CurrentCell.RowIndex + 1; i <= this.gridDataBoundGrid1.Model.RowCount; ++i) { if(this.gridDataBoundGrid1.IsExpandedAtRowIndex(i) && list == gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(i).ChildList) { parentRow = i; break; } } } //the readon for breaking things at the current row is that most of teh time, it //is the current row that is of interest..... } return parentRow; } //this opens & closes the node at row private void RefreshRow(int row) { GridBoundRecordState state = gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(row); if(this.gridDataBoundGrid1.IsExpandedAtRowIndex(row) && state != null && state.ChildCount > 0) { //slave the expand states of the node''s children bool[] expandState = new bool[state.ChildCount]; for(int i = 0; i < state.ChildCount; ++i) expandState[i] = this.gridDataBoundGrid1.IsExpandedAtRowIndex(row + i + 1); //close & open the node this.gridDataBoundGrid1.BeginUpdate(); this.gridDataBoundGrid1.CollapseAtRowIndex(row); this.gridDataBoundGrid1.ExpandAtRowIndex(row); //restore the expand states for(int i = 0; i < state.ChildCount; ++i) { if(i < expandState.GetUpperBound(0) && expandState[i]) this.gridDataBoundGrid1.ExpandAtRowIndex(row + i + 1); } this.gridDataBoundGrid1.EndUpdate(); } } // Counts the number of screenrows used by the children of the given row. // Uses recursion to loop through all the child levels of a given row adding // up the visible child rows. private int ScreenRowsInChildren(int row) { int rowCount = 0; if(gridDataBoundGrid1.IsExpandedAtRowIndex(row) ) { GridBoundRecordState state = gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(row); if(state != null && state.ChildList != null) { for(int i = 0; i < state.ChildCount; ++i) { rowCount += 1 + ScreenRowsInChildren(row + i + 1); } } } return rowCount; } #endregion #region The DataTables private int numberOfGrandChildren = 50; private int numberOfChildren = 20; private int numberOfParents = 5; private Random r = new Random(); private DataTable GetParentTable() { DataTable dt = new DataTable("ParentTable"); dt.Columns.Add(new DataColumn("parentID")); //lower case p dt.Columns.Add(new DataColumn("ParentName")); for(int i = 0; i < numberOfParents; ++i) { DataRow dr = dt.NewRow(); dr[0] = i.ToString(); dr[1] = string.Format("parentName{0}", i); dt.Rows.Add(dr); } return dt; } private DataTable GetChildTable() { DataTable dt = new DataTable("ChildTable"); dt.Columns.Add(new DataColumn("childID")); //lower case c dt.Columns.Add(new DataColumn("Name")); dt.Columns.Add(new DataColumn("ParentID")); //upper case P for(int i = 0; i < numberOfChildren; ++i) { DataRow dr = dt.NewRow(); dr[0] = i.ToString(); dr[1] = string.Format("ChildName{0}",i); dr[2] = r.Next(numberOfParents).ToString(); dt.Rows.Add(dr); } return dt; } private DataTable GetGrandChildTable() { int numSports = 5; string[] sports = new string[]{"baseball","soccer","football","basketball","golf"}; DataTable dt = new DataTable("GrandChildTable"); dt.Columns.Add(new DataColumn("GrandChildID")); dt.Columns.Add(new DataColumn("Name")); dt.Columns.Add(new DataColumn("ChildID")); //upper case C dt.Columns.Add(new DataColumn("FavSport")); //upper case C for(int i = 0; i < numberOfGrandChildren; ++i) { DataRow dr = dt.NewRow(); dr[0] = i.ToString(); dr[1] = string.Format("GrandChildName{0}",i); dr[2] = r.Next(numberOfChildren).ToString(); dr[3] = sports[r.Next(numSports)]; dt.Rows.Add(dr); } return dt; } #endregion } } Thanks Satish >Hello. >How to implement "Delete" button not only for top-level table row, but for child rows too. >Thanks. >Current code: >private void button2_Click(object sender, System.EventArgs e) > { > Record r = this.gridGroupingControl1.Table.CurrentRecord; > if(r != null) > { > r.Delete(); > } > }


AD Administrator Syncfusion Team July 6, 2004 07:34 AM UTC

I am confused. There does not seem to be any gridGroupingControl1 in the code you pasted, but you initial post seemed to be asking about gridGroupingControl?


AD Administrator Syncfusion Team July 6, 2004 07:40 AM UTC

The code above is not for GridGroupingControl. :(


AD Administrator Syncfusion Team July 6, 2004 01:17 PM UTC

If you are using nested tables, you need to do more work to get at the current record. Attached is a little sample. That works if you select a record without any children. But right now, it trhoughs an exception if you try to delete a record with children. This is a bug that we will correct. MonthCalendar_1424.zip


AD Administrator Syncfusion Team February 7, 2006 02:59 AM UTC

>Here is the code... > >using System; >using System.Drawing; >using System.Collections; >using System.ComponentModel; >using System.Windows.Forms; >using System.Data; >using Syncfusion.Windows.Forms.Grid; > >namespace UpdateableExpandGrid >{ > /// > /// Summary description for Form1. > /// > public class Form1 : System.Windows.Forms.Form > { > private GridDataBoundGrid gridDataBoundGrid1; > private System.Windows.Forms.Button buttonExpandAll; > private System.Windows.Forms.Button buttonCollapseAll; > private System.Windows.Forms.Button buttonChangeValue; > private System.Windows.Forms.Button buttonDeleteRow; > private System.Windows.Forms.Button buttonInsertRow; > /// > /// Required designer variable. > /// > private System.ComponentModel.Container components = null; > > public Form1() > { > // > // Required for Windows Form Designer support > // > InitializeComponent(); > > // > // TODO: Add any constructor code after InitializeComponent call > // > } > > /// > /// Clean up any resources being used. > /// > protected override void Dispose( bool disposing ) > { > if( disposing ) > { > if (components != null) > { > components.Dispose(); > } > } > base.Dispose( disposing ); > } > > #region Windows Form Designer generated code > /// > /// Required method for Designer support - do not modify > /// the contents of this method with the code editor. > /// > private void InitializeComponent() > { > this.gridDataBoundGrid1 = new Syncfusion.Windows.Forms.Grid.GridDataBoundGrid(); > this.buttonExpandAll = new System.Windows.Forms.Button(); > this.buttonCollapseAll = new System.Windows.Forms.Button(); > this.buttonChangeValue = new System.Windows.Forms.Button(); > this.buttonDeleteRow = new System.Windows.Forms.Button(); > this.buttonInsertRow = new System.Windows.Forms.Button(); > ((System.ComponentModel.ISupportInitialize)(this.gridDataBoundGrid1)).BeginInit(); > this.SuspendLayout(); > // > // gridDataBoundGrid1 > // > this.gridDataBoundGrid1.AllowDragSelectedCols = true; > this.gridDataBoundGrid1.Anchor = (((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) > | System.Windows.Forms.AnchorStyles.Left) > | System.Windows.Forms.AnchorStyles.Right); > this.gridDataBoundGrid1.Location = new System.Drawing.Point(16, 56); > this.gridDataBoundGrid1.Name = "gridDataBoundGrid1"; > this.gridDataBoundGrid1.ShowCurrentCellBorderBehavior = Syncfusion.Windows.Forms.Grid.GridShowCurrentCellBorder.GrayWhenLostFocus; > this.gridDataBoundGrid1.Size = new System.Drawing.Size(520, 288); > this.gridDataBoundGrid1.SortBehavior = Syncfusion.Windows.Forms.Grid.GridSortBehavior.DoubleClick; > this.gridDataBoundGrid1.TabIndex = 0; > this.gridDataBoundGrid1.Text = "gridDataBoundGrid1"; > // > // buttonExpandAll > // > this.buttonExpandAll.Location = new System.Drawing.Point(16, 16); > this.buttonExpandAll.Name = "buttonExpandAll"; > this.buttonExpandAll.TabIndex = 1; > this.buttonExpandAll.Text = "ExpandAll"; > this.buttonExpandAll.Click += new System.EventHandler(this.buttonExpandAll_Click); > // hjvjhvjh > // buttonCollapseAll > // > this.buttonCollapseAll.Location = new System.Drawing.Point(88, 16); > this.buttonCollapseAll.Name = "buttonCollapseAll"; > this.buttonCollapseAll.TabIndex = 2; > this.buttonCollapseAll.Text = "CollapseAll"; > this.buttonCollapseAll.Click += new System.EventHandler(this.buttonCollapseAll_Click); > // > // buttonChangeValue > // > this.buttonChangeValue.Location = new System.Drawing.Point(160, 16); > this.buttonChangeValue.Name = "buttonChangeValue"; > this.buttonChangeValue.Size = new System.Drawing.Size(152, 23); > this.buttonChangeValue.TabIndex = 3; > this.buttonChangeValue.Text = "ChangeValueInCurrentRow"; > this.buttonChangeValue.Click += new System.EventHandler(this.buttonChangeValue_Click); > // > // buttonDeleteRow > // > this.buttonDeleteRow.Location = new System.Drawing.Point(312, 16); > this.buttonDeleteRow.Name = "buttonDeleteRow"; > this.buttonDeleteRow.Size = new System.Drawing.Size(112, 23); > this.buttonDeleteRow.TabIndex = 4; > this.buttonDeleteRow.Text = "DeleteCurrentRow"; > this.buttonDeleteRow.Click += new System.EventHandler(this.buttonDeleteRow_Click); > // > // buttonInsertRow > // > this.buttonInsertRow.Location = new System.Drawing.Point(424, 16); > this.buttonInsertRow.Name = "buttonInsertRow"; > this.buttonInsertRow.Size = new System.Drawing.Size(112, 23); > this.buttonInsertRow.TabIndex = 5; > this.buttonInsertRow.Text = "InsertAtCurrentRow"; > this.buttonInsertRow.Click += new System.EventHandler(this.buttonInsertRow_Click); > // > // Form1 > // > this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); > this.ClientSize = new System.Drawing.Size(552, 358); > this.Controls.AddRange(new System.Windows.Forms.Control[] { > this.buttonInsertRow, > this.buttonDeleteRow, > this.buttonChangeValue, > this.buttonCollapseAll, > this.buttonExpandAll, > this.gridDataBoundGrid1}); > this.Name = "Form1"; > this.Text = "Form1"; > this.Load += new System.EventHandler(this.Form1_Load); > ((System.ComponentModel.ISupportInitialize)(this.gridDataBoundGrid1)).EndInit(); > this.ResumeLayout(false); > > } > #endregion > > /// > /// The main entry point for the application. > /// > [STAThread] > static void Main() > { > Application.Run(new Form1()); > } > > private DataSet dSet; > GridHierarchyLevel hlParentToChild; > GridHierarchyLevel hlChildToGrandChild; > GridHierarchyLevel hlParent; > > private void Form1_Load(object sender, System.EventArgs e) > { > //dataset ============================================== > dSet = new DataSet(); > > DataTable parentTable = GetParentTable(); > DataTable childTable = GetChildTable(); > DataTable grandChildTable = GetGrandChildTable(); > dSet.Tables.AddRange(new DataTable[]{parentTable, childTable, grandChildTable}); > > //setup the relations ======================================== > DataColumn parentColumn = parentTable.Columns["parentID"]; > DataColumn childColumn = childTable.Columns["ParentID"]; > dSet.Relations.Add("ParentToChild", parentColumn, childColumn); > > parentColumn = childTable.Columns["childID"]; > childColumn = grandChildTable.Columns["ChildID"]; > dSet.Relations.Add("ChildToGrandChild", parentColumn, childColumn); > > //expand grid =================================================== > this.gridDataBoundGrid1.DataSource = parentTable; > hlParentToChild = this.gridDataBoundGrid1.Binder.AddRelation("ParentToChild"); > hlChildToGrandChild = this.gridDataBoundGrid1.Binder.AddRelation("ChildToGrandChild"); > hlParent = this.gridDataBoundGrid1.Binder.RootHierarchyLevel; > > //hlParentToChild.ShowHeaders = false; > //hlChildToGrandChild.ShowHeaders = false; > //hlParent.ShowHeaders = false; > > //setup the parentgridlayout > hlParent.LayoutColumns(new string[]{"parentID", "ParentName", " ", " "}); > this.gridDataBoundGrid1.Model.CoveredRanges.Add(GridRangeInfo.Cells(0, 4, 0, 5)); > > //gray the last 2 columns > GridStyleInfo style = hlParent.InternalColumns[2].StyleInfo; > style.Borders.All = new GridBorder(GridBorderStyle.None); > style.BackColor = SystemColors.Control; > style.CellType = "Static"; > style.Enabled = false; > > style = hlParent.InternalColumns[3].StyleInfo; > style.Borders.All = new GridBorder(GridBorderStyle.None); > style.BackColor = SystemColors.Control; > style.CellType = "Static"; > style.Enabled = false; > > hlParent.RowStyle.BackColor = Color.PaleGoldenrod; > > //setup the child gridlayout > hlParentToChild.LayoutColumns(new string[]{"childID", "Name", "ParentID", " "}); > //gray the last column > style = hlParentToChild.InternalColumns[3].StyleInfo; > style.Borders.All = new GridBorder(GridBorderStyle.None); > style.BackColor = SystemColors.Control; > style.CellType = "Static"; > style.Enabled = false; > > hlParentToChild.RowStyle.BackColor = Color.LightGoldenrodYellow; > > this.gridDataBoundGrid1.AllowResizeToFit = false; > this.gridDataBoundGrid1.Model.ColWidths.ResizeToFit(GridRangeInfo.Rows(0, 2), GridResizeToFitOptions.IncludeHeaders); > > this.gridDataBoundGrid1.Model.ColWidths[1] = 20; > this.gridDataBoundGrid1.Model.ColWidths[3] = 120; > > //handle Row expanding/collapse to hook bindlinglist.ListChanged event > // for the child tables > this.gridDataBoundGrid1.RowCollapsing += new GridRowEventHandler(grid_RowCollapsing); > this.gridDataBoundGrid1.RowExpanded += new GridRowEventHandler(grid_RowExpanded); > > //handle to listen to teh changed event for the parent table > CurrencyManager cm = (CurrencyManager)this.BindingContext[this.gridDataBoundGrid1.DataSource, this.gridDataBoundGrid1.DataMember]; > ((IBindingList)cm.List).ListChanged += new ListChangedEventHandler(list_ListChanged); > } > > #region Dynamically hooking and unhooking ListChanged event > > //ParentNodesOfExpandedNodes holds a list of parent nodes: key - parent nodes value- arraylist of ChildLists > // used when a parent node is close so all children listchanged event handlers can be unhooked > private Hashtable ParentNodesOfExpandedNodes = new Hashtable(); > > //hook the ListChange event for the node that opened > //and save its parent node in the ParentNodesOfExpandedNodes hashtable > private void grid_RowExpanded(object sender, GridRowEventArgs e) > { > GridBoundRecordState state = gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(e.RowIndex); > > if(state.ChildList != null) > { > ((IBindingList)state.ChildList).ListChanged += new ListChangedEventHandler(list_ListChanged); > Console.WriteLine(" HOOKED " + e.RowIndex.ToString()); > if(state.Parent != null) > { > SaveParentNode(state); > } > } > } > > //help method that save the parent node of an expanded child > // so, later if you close teh paerent, the child''s listchanged event can also be unhooked > private void SaveParentNode(GridBoundRecordState state) > { > if(ParentNodesOfExpandedNodes.ContainsKey(state.Parent)) > { > ArrayList al = (ArrayList)ParentNodesOfExpandedNodes[state.Parent]; > al.Add(state.ChildList); > } > else > { > ArrayList al = new ArrayList(); > al.Add(state.ChildList); > ParentNodesOfExpandedNodes.Add(state.Parent, al); > } > } > > //here we unhook the ListChnaged event for teh node this closing > //as well as any child ListChanged event that is hooked > private void grid_RowCollapsing(object sender, GridRowEventArgs e) > { > ResetNodeAndChildNodesAtRow(e.RowIndex); > } > > //helper method that unhooks teh ListChanged event of teh row plus as well > // as the listchanged events of any children node. Uses the ParentNodesOfExpandedNodes hahtable > // to get at the children > private void ResetNodeAndChildNodesAtRow(int row) > { > GridBoundRecordState state = gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(row); > if(state.ChildList != null) > { > ((IBindingList)state.ChildList).ListChanged -= new ListChangedEventHandler(list_ListChanged); > Console.WriteLine("UNHOOKED " + row.ToString()); > } > if(ParentNodesOfExpandedNodes.ContainsKey(state)) > { > ArrayList al = (ArrayList)ParentNodesOfExpandedNodes[state]; > foreach(IBindingList list in al) > { > list.ListChanged -= new ListChangedEventHandler(list_ListChanged); > Console.WriteLine("UNHOOKEDc " + row.ToString()); > } > ParentNodesOfExpandedNodes.Remove(state); > } > } > > #endregion > > #region ListChanged event handler that reacts to child changes > > private void list_ListChanged(object sender, ListChangedEventArgs e) > { > IBindingList list = (IBindingList) sender; > if(list != null) > { > //find the parent row... > int parentRow = findParentRowFromChildList(list); > if(parentRow == -1) > { > //we have a parent row. Check for change. > if(e.ListChangedType == ListChangedType.ItemChanged) > { > > UpdateThisParentRow(e.NewIndex); > } > else if(e.ListChangedType == ListChangedType.ItemAdded || > e.ListChangedType == ListChangedType.ItemDeleted) > { > UpdateThisParentRow(e.NewIndex); > this.gridDataBoundGrid1.Refresh(); > } > > return; > } > > //recurs = 0; > int screenRow = parentRow + e.NewIndex + 1;// - this.gridDataBoundGrid1.TopRowIndex - 1; > for(int j = 1; j <= e.NewIndex; ++j) > screenRow += ScreenRowsInChildren(parentRow + j); > > > Console.WriteLine("Item#=" + e.NewIndex.ToString() + " parentRow: " + parentRow.ToString() + " screenRow: " + screenRow.ToString()); > > switch(e.ListChangedType) > { > case ListChangedType.ItemChanged: > //just redraw screen row to show the change > this.gridDataBoundGrid1.RefreshRange(GridRangeInfo.Row(screenRow)); > Console.WriteLine("ItemChanged"); > break; > case ListChangedType.ItemAdded: > //this opens & closes the parent node > RefreshRow(parentRow); > > //put the currentcell somewhere > this.gridDataBoundGrid1.Focus(); > this.gridDataBoundGrid1.CurrentCell.Activate(screenRow - 1, 2); //minus 1 because of new row > Console.WriteLine("ItemAdded"); > > break; > case ListChangedType.ItemDeleted: > //this opens & closes the parent node > RefreshRow(parentRow); > > //put the currentcell somewhere > this.gridDataBoundGrid1.Focus(); > this.gridDataBoundGrid1.CurrentCell.Activate(screenRow, 2); //minus 1 because of new row > Console.WriteLine("ItemDeleted"); > break; > default: > break; > } > } > } > > #endregion > > #region Button clicks > private void buttonExpandAll_Click(object sender, System.EventArgs e) > { > this.gridDataBoundGrid1.ExpandAll(); > } > > private void buttonCollapseAll_Click(object sender, System.EventArgs e) > { > this.gridDataBoundGrid1.CollapseAll(); > } > > private void buttonChangeValue_Click(object sender, System.EventArgs e) > { > GridCurrentCell cc = this.gridDataBoundGrid1.CurrentCell; > > //change a value in the underlying datasource somehow > //here we know the object is a datarowview > GridBoundRecordState rs = this.gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(cc.RowIndex); > object o = rs.ListManager.Current; > DataRowView drv = (DataRowView) o; > DataRow dr = drv.Row; > dr[1] = "Changed.."; > drv.EndEdit(); > > } > > private void buttonDeleteRow_Click(object sender, System.EventArgs e) > { > DataTable dt = this.dSet.Tables[0]; > > GridCurrentCell cc = this.gridDataBoundGrid1.CurrentCell; > int row = cc.RowIndex; > int col = cc.ColIndex; > GridBoundRecordState rs = this.gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(cc.RowIndex); > > //remove the current record > int i = rs.ListManager.Position; > rs.ListManager.Position = i - 1; > rs.ListManager.RemoveAt(i); > > RefreshCurrentParentNode(rs.ListManager.Position - 1); > if(row >= this.gridDataBoundGrid1.Model.RowCount) > row = row - 1; > > this.gridDataBoundGrid1.CurrentCell.MoveTo(row, col); > } > > private void buttonInsertRow_Click(object sender, System.EventArgs e) > { > GridCurrentCell cc = this.gridDataBoundGrid1.CurrentCell; > GridBoundRecordState rs = this.gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(cc.RowIndex); > > //add a new record to the same level > object o = rs.ListManager.Current; > DataRowView drv = (DataRowView) o; > DataRow dr = drv.Row; > > DataTable dt = this.dSet.Tables[rs.LevelIndex]; //get the table > DataRow newRow = dt.NewRow(); > object[] values = null; > switch(rs.LevelIndex) > { > case 0: > this.numberOfParents += 1; > //pkValue = this.numberOfParents; > values = new object[]{this.numberOfParents, string.Format("parentName{0}", this.numberOfParents)}; > break; > case 1: > this.numberOfChildren += 1; > //pkValue = this.numberOfChildren; > values = new object[]{this.numberOfChildren, string.Format("ChildName{0}",this.numberOfChildren), dr[2]}; > break; > case 2: > this.numberOfGrandChildren += 1; > //pkValue = this.numberOfGrandChildren; > values = new object[]{this.numberOfGrandChildren, string.Format("GrandChildName{0}",numberOfGrandChildren), dr[2], dr[3]}; > break; > default: > throw new IndexOutOfRangeException("Improper index"); > > } > > newRow.ItemArray = values; > dt.Rows.Add(newRow); > > > RefreshCurrentParentNode(dt.Rows.Count); > > } > > #endregion > > #region helper methods > > //refreshes the row form the tableIndex position > private void UpdateThisParentRow(int tableIndex) > { > for(int row = this.gridDataBoundGrid1.Model.Rows.HeaderCount + 1; row <= this.gridDataBoundGrid1.ViewLayout.LastVisibleRow; ++row) > { > if(this.gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(row).LevelIndex == 0) > { > if(tableIndex == 0) > { > this.gridDataBoundGrid1.RefreshRange(GridRangeInfo.Row(row)); > this.gridDataBoundGrid1.Model.ResetVolatileData(); > return; > } > tableIndex--; > } > } > } > > private void RefreshCurrentParentNode(int position) > { > //if the new row should be visible, then open & close its parent to rebind it... > > GridCurrentCell cc = this.gridDataBoundGrid1.CurrentCell; > //change a value in the underlying datasource somehow > //here we know the object is a datarowview > GridBoundRecordState rs = this.gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(cc.RowIndex); > > > if(rs.LevelIndex == 0) > { > int r = Math.Max(0, this.gridDataBoundGrid1.Binder.PositionToRowIndex(position)); > gridDataBoundGrid1.CurrentCell.MoveTo(r, 1); > gridDataBoundGrid1.RefreshRange(GridRangeInfo.Table()); > return; > } > int parentLevel = rs.LevelIndex - 1; > > > > int row = cc.RowIndex - 1; > > while (row > this.gridDataBoundGrid1.Model.Rows.HeaderCount) > { > rs = this.gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(row); > if(rs.LevelIndex == parentLevel) > break; > row -= 1; > } > > if(row > this.gridDataBoundGrid1.Model.Rows.HeaderCount) > { > this.gridDataBoundGrid1.Model.BeginUpdate(); > this.gridDataBoundGrid1.CollapseAtRowIndex(row); > this.gridDataBoundGrid1.ExpandAtRowIndex(row); > this.gridDataBoundGrid1.CollapseAtRowIndex(row); > this.gridDataBoundGrid1.ExpandAtRowIndex(row); > > this.gridDataBoundGrid1.Model.EndUpdate(); > > } > > } > > > > // locates the parent row for a given childlist > private int findParentRowFromChildList(IBindingList list) > { > int parentRow = -1; > if(list != null) > { > //it looks first from the current row up > for(int i = this.gridDataBoundGrid1.CurrentCell.RowIndex; i > this.gridDataBoundGrid1.Model.Rows.HeaderCount; --i) > { > if(this.gridDataBoundGrid1.IsExpandedAtRowIndex(i) && > list == gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(i).ChildList) > { > parentRow = i; > break; > } > } > > //if it doesn''t find it, it looks in teh second half > if(parentRow == -1) > { > for(int i = this.gridDataBoundGrid1.CurrentCell.RowIndex + 1; i <= this.gridDataBoundGrid1.Model.RowCount; ++i) > { > if(this.gridDataBoundGrid1.IsExpandedAtRowIndex(i) && > list == gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(i).ChildList) > { > parentRow = i; > break; > } > } > } > > //the readon for breaking things at the current row is that most of teh time, it > //is the current row that is of interest..... > } > return parentRow; > } > > > //this opens & closes the node at row > private void RefreshRow(int row) > { > GridBoundRecordState state = gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(row); > if(this.gridDataBoundGrid1.IsExpandedAtRowIndex(row) > && state != null && state.ChildCount > 0) > { > //slave the expand states of the node''s children > bool[] expandState = new bool[state.ChildCount]; > for(int i = 0; i < state.ChildCount; ++i) > expandState[i] = this.gridDataBoundGrid1.IsExpandedAtRowIndex(row + i + 1); > > //close & open the node > this.gridDataBoundGrid1.BeginUpdate(); > this.gridDataBoundGrid1.CollapseAtRowIndex(row); > this.gridDataBoundGrid1.ExpandAtRowIndex(row); > > //restore the expand states > for(int i = 0; i < state.ChildCount; ++i) > { > if(i < expandState.GetUpperBound(0) && expandState[i]) > this.gridDataBoundGrid1.ExpandAtRowIndex(row + i + 1); > } > this.gridDataBoundGrid1.EndUpdate(); > } > } > > // Counts the number of screenrows used by the children of the given row. > // Uses recursion to loop through all the child levels of a given row adding > // up the visible child rows. > private int ScreenRowsInChildren(int row) > { > int rowCount = 0; > if(gridDataBoundGrid1.IsExpandedAtRowIndex(row) ) > { > GridBoundRecordState state = gridDataBoundGrid1.Binder.GetRecordStateAtRowIndex(row); > if(state != null && state.ChildList != null) > { > for(int i = 0; i < state.ChildCount; ++i) > { > rowCount += 1 + ScreenRowsInChildren(row + i + 1); > } > > } > } > return rowCount; > } > > #endregion > > #region The DataTables > > private int numberOfGrandChildren = 50; > private int numberOfChildren = 20; > private int numberOfParents = 5; > > private Random r = new Random(); > > private DataTable GetParentTable() > { > DataTable dt = new DataTable("ParentTable"); > > dt.Columns.Add(new DataColumn("parentID")); //lower case p > dt.Columns.Add(new DataColumn("ParentName")); > > for(int i = 0; i < numberOfParents; ++i) > { > DataRow dr = dt.NewRow(); > dr[0] = i.ToString(); > dr[1] = string.Format("parentName{0}", i); > dt.Rows.Add(dr); > } > > return dt; > } > > private DataTable GetChildTable() > { > DataTable dt = new DataTable("ChildTable"); > > dt.Columns.Add(new DataColumn("childID")); //lower case c > dt.Columns.Add(new DataColumn("Name")); > dt.Columns.Add(new DataColumn("ParentID")); //upper case P > > > for(int i = 0; i < numberOfChildren; ++i) > { > DataRow dr = dt.NewRow(); > dr[0] = i.ToString(); > dr[1] = string.Format("ChildName{0}",i); > dr[2] = r.Next(numberOfParents).ToString(); > dt.Rows.Add(dr); > } > > return dt; > } > > private DataTable GetGrandChildTable() > { > int numSports = 5; > string[] sports = new string[]{"baseball","soccer","football","basketball","golf"}; > > DataTable dt = new DataTable("GrandChildTable"); > > dt.Columns.Add(new DataColumn("GrandChildID")); > dt.Columns.Add(new DataColumn("Name")); > dt.Columns.Add(new DataColumn("ChildID")); //upper case C > dt.Columns.Add(new DataColumn("FavSport")); //upper case C > > for(int i = 0; i < numberOfGrandChildren; ++i) > { > DataRow dr = dt.NewRow(); > dr[0] = i.ToString(); > dr[1] = string.Format("GrandChildName{0}",i); > dr[2] = r.Next(numberOfChildren).ToString(); > dr[3] = sports[r.Next(numSports)]; > dt.Rows.Add(dr); > } > > return dt; > } > #endregion > > } >} > >Thanks >Satish > >>Hello. >>How to implement "Delete" button not only for top-level table row, but for child rows too. >>Thanks. >>Current code: >>private void button2_Click(object sender, System.EventArgs e) >> { >> Record r = this.gridGroupingControl1.Table.CurrentRecord; >> if(r != null) >> { >> r.Delete(); >> } >> }

Loader.
Live Chat Icon For mobile
Up arrow icon