/// <summary> /// Set timer clok to notify the changes /// </summary> private void m_timer_Tick(object sender, EventArgs e) { timerCount++; GridRangeInfo gCells = GridRangeInfo.EmptyRange(); if (oldSize != m_syncGrid.ClientSize) { // Dispose graphics context if size was changed. if (g != null) { g.Dispose(); } g = null; oldSize = m_syncGrid.ClientSize; } if (drawDirectToDC && g == null) { g = m_syncGrid.CreateGridGraphics(); } try { for (int i = 0; i < m_numUpdatesPerTick; i++) { int recNum = rand.Next(m_set.Count - 1); int rowNum = recNum + 1; int col = rand.Next(18) + 1; int colNum = col + 1; object[] drow = (object[])m_set[recNum]; drow[col] = rand.Next(100); GridRangeInfo g1 = GridRangeInfo.Cell(rowNum, colNum); gCells = GridRangeInfo.UnionRange(gCells, g1); // Clear our volatile cache m_syncGrid.ResetVolatileData(); // Handle case when values is change for current cell. if (g1 == m_syncGrid.CurrentCell.RangeInfo) { m_syncGrid.CurrentCell.Model.ResetActiveText(rowNum, colNum); } else { // Draw direct to dc if (drawDirectToDC) { Rectangle bounds = m_syncGrid.RangeInfoToRectangle(g1); if (!bounds.IsEmpty) { // DrawClippedGrid method lets you simply draw the cells at the specified bounds directly to the graphics context. m_syncGrid.DrawClippedGrid(g, bounds); } } } } if (!drawDirectToDC) { m_syncGrid.ResetVolatileData(); m_syncGrid.ViewLayout.Lock(); // Prevent subsequent calls to ViewLayout.Reset method from clearing the layout information. Method was added in 3.1.0.x Rectangle bounds = m_syncGrid.RangeInfoToRectangle(gCells); if (!bounds.IsEmpty) { m_syncGrid.Invalidate(bounds); m_syncGrid.Update(); } m_syncGrid.ViewLayout.Unlock(); } // Insert or remove a row if (insertRemoveCount == 0) { return; } if (toggleInsertRemove > 0 && (timerCount % insertRemoveModulus) == 0) { icount = ++icount % (toggleInsertRemove * 2); shouldInsert = icount <= toggleInsertRemove; Console.WriteLine(m_syncGrid.RowCount); if (shouldInsert) { for (int ri = 0; ri < insertRemoveCount; ri++) { int recNum = rand.Next(m_set.Count - 1); int rowNum = recNum + 1; // Underlying data structure (this could be a datatable or whatever structure // you use behind a virtual grid). // // In this case it is a ArrayList int next = rand.Next(100); object[] row = new object[] { "Hello world", next + 1, next + 2, next + 3, next + 4, next + 5, next + 6, next + 7, next + 8, next + 9, next + 10, next + 11, next + 12, next + 13, next + 14, next + 15, next + 16, next + 17, next + 18, next + 19, next + 20 }; m_set.Insert(recNum, row); // Now that the change was done in the underlying datasource we need // to tell the grid to reflect those changes: m_syncGrid.Model.ResetVolatileData(); // Old way: if (!drawDirectToDC) { m_syncGrid.Rows.OnRangeInserting(new GridRangeInsertingEventArgs(rowNum, 1, null)); m_syncGrid.Rows.OnRangeInserted(new GridRangeInsertedEventArgs(rowNum, 1, null, true)); m_syncGrid.Update(); } else { // Optimized way: Directly calling ScrollWindows, don't let ScrollWindow call Invalidate. if (rowNum < m_syncGrid.TopRowIndex) { if (!allowChangeTopRowWhenInsertBeforeView || !m_syncGrid.ViewLayout.HasPartialVisibleRows) // checks whether the last row is shown and fully visible { // in this case we need to insert at top rowNum = m_syncGrid.TopRowIndex; } else { // If record is inserted before viewable area, simply increase // the top row so that the viewable area stays the same. No // drawing of the screen is needed. m_syncGrid.InternalSetTopRow(m_syncGrid.TopRowIndex + 1); m_syncGrid.UpdateScrollBars(); rowNum = -1; // mark it as handled. if (showNumberedRowHeaders) { // Repaint only row headers - they all change Rectangle rowHeaderBounds = m_syncGrid.RangeInfoToRectangle(GridRangeInfo.Col(0)); m_syncGrid.DrawClippedGrid(g, rowHeaderBounds); } } } if (rowNum != -1) { GridRangeInfo rg = GridRangeInfo.Row(rowNum); Rectangle bounds = m_syncGrid.RangeInfoToRectangle(rg); if (!bounds.IsEmpty) { if (showNumberedRowHeaders) { // don't scroll row header area - leave it as is (only works if all rows have same height ...) bounds.X += m_syncGrid.ColWidths[0]; if (!m_syncGrid.ViewLayout.HasPartialVisibleRows) { // Repaint row headers below last row Rectangle rowHeaderBounds = m_syncGrid.RangeInfoToRectangle(GridRangeInfo.Cells(m_syncGrid.RowCount, 0, m_syncGrid.RowCount, 0)); m_syncGrid.DrawClippedGrid(g, rowHeaderBounds); } } // If rows can have different heights: // m_syncGrid.ViewLayout.Reset(); Rectangle scrollBounds = new Rectangle(bounds.Left, bounds.Top, bounds.Right, m_syncGrid.ClientRectangle.Bottom); m_syncGrid.ScrollWindow(0, bounds.Height, scrollBounds, scrollBounds, false); // don't cause Invalidate being called. m_syncGrid.Model.ResetVolatileData(); // System.Threading.Thread.Sleep(1000); // DrawClippedGrid method lets you simply draw the cells at the specified bounds directly to the graphics context. m_syncGrid.DrawClippedGrid(g, bounds); } m_syncGrid.UpdateScrollBars(); } } } } else { for (int ri = 0; ri < insertRemoveCount; ri++) { int recNum = 5; //rand.Next(m_set.Count - 1); int rowNum = recNum + 1; // Underlying data structure (this could be a datatable or whatever structure // you use behind a virtual grid). // // In this case it is a ArrayList m_set.RemoveAt(recNum); // Now that the change was done in the underlying datasource we need // to tell the grid to reflect those changes: // Old way: if (!drawDirectToDC) { m_syncGrid.Rows.OnRangeRemoving(new GridRangeRemovingEventArgs(rowNum, rowNum + 1)); GridModelInsertRangeOptions iro = new GridModelInsertRangeOptions(); iro.RowColSizes = new int[m_syncGrid.Rows.DefaultSize]; m_syncGrid.Rows.OnRangeRemoved(new GridRangeRemovedEventArgs(rowNum, rowNum + 1, iro, true)); m_syncGrid.Update(); } else { // Optimized way: Directly calling ScrollWindows, don't let ScrollWindow call Invalidate. if (rowNum < m_syncGrid.TopRowIndex) { if (!allowChangeTopRowWhenInsertBeforeView || !m_syncGrid.ViewLayout.HasPartialVisibleRows) // checks whether the last row is shown and fully visible { // in this case we need to insert at top rowNum = m_syncGrid.TopRowIndex; } else { // If record is inserted before viewable area, simply increase // the top row so that the viewable area stays the same. No // drawing of the screen is needed. m_syncGrid.InternalSetTopRow(m_syncGrid.TopRowIndex - 1); m_syncGrid.UpdateScrollBars(); if (showNumberedRowHeaders) { // Repaint only row headers - they all change Rectangle rowHeaderBounds = m_syncGrid.RangeInfoToRectangle(GridRangeInfo.Col(0)); m_syncGrid.DrawClippedGrid(g, rowHeaderBounds); } rowNum = -1; // mark it as handled. } } if (rowNum != -1) { GridRangeInfo rg = GridRangeInfo.Row(rowNum); Rectangle bounds = m_syncGrid.RangeInfoToRectangle(rg); if (!bounds.IsEmpty) { if (showNumberedRowHeaders) { // don't scroll row header area - leave it as is (only works if all rows have same height ...) bounds.X += m_syncGrid.ColWidths[0]; } // If rows can have different heights: // m_syncGrid.ViewLayout.Reset(); Rectangle scrollBounds = new Rectangle(bounds.Left, bounds.Top, bounds.Right, m_syncGrid.ClientRectangle.Bottom); Rectangle scrolledInViewBounds = m_syncGrid.ScrollWindow(0, -bounds.Height, scrollBounds, scrollBounds, false); // don't cause Invalidate being called. m_syncGrid.Model.ResetVolatileData(); // DrawClippedGrid method lets you simply draw the cells at the specified bounds directly to the graphics context. if (!m_syncGrid.ViewLayout.HasPartialVisibleRows) { scrolledInViewBounds = new Rectangle(0, m_syncGrid.ViewLayout.Corner.Y, bounds.Right, bounds.Height); } m_syncGrid.DrawClippedGrid(g, scrolledInViewBounds); } m_syncGrid.UpdateScrollBars(); } } } } } } finally { } }