+ // create string-based MultiColumnDictionary and assign it to column
+ // note: this will automatically generate keys of type 'int' for each item,
+ // the key values will be stored in the grid.
+ string text = "Row1, Col1\tRow1, Col2|Row2, Col1\tRow2, Col3|Row2, Col1\tRow3, Col2";
+ MultiColumnDictionary map = new MultiColumnDictionary(text, 0, true);
+ _flex.Cols[1].DataMap = map;
+
+
+ // create data-based MultiColumnDictionary and assign it to column
+ // notes: the list will automatically be updated is the data source changes.
+ DataTable dt = GetDataTable("employees");
+ string[] columnNames = new string[] { "FirstName", "LastName", "Country" };
+ MultiColumnDictionary map = new MultiColumnDictionary(dt, "EmployeeID", columnNames, 1);
+ _flex.Cols[2].DataMap = map;
+
+
+ [LicenseProvider(typeof(LicenseProvider))]
+ public class MyGrid : C1FlexGrid
+ {
+ // implementation
+ }
+
+
+ flex.AllowMerging = AllowMergingEnum.Free;
+ flex.Cols[1].AllowMerging = true; // merge values in column 1
+
+ private void _flex_SelChange(object sender, System.EventArgs e)
+ {
+ CellRange rg = this._flex.GetMergedRange(_flex.Row, _flex.Col, false);
+ if (!rg.IsSingleCell)
+ {
+ Console.WriteLine("selection is merged: {0},{1}-{2},{3}",
+ rg.TopRow, rg.LeftCol, rg.BottomRow, rg.RightCol);
+ }
+ }
+
+ The code below shows how you can override the
+ public class CustomMerge : C1FlexGrid
+ {
+ public CustomMerge()
+ {
+ // allow free merging by default
+ AllowMerging = AllowMergingEnum.Free;
+ for (int r = 0; r < Rows.Count; r++) Rows[r].AllowMerging = true;
+ for (int c = 0; c < Cols.Count; c++) Cols[c].AllowMerging = true;
+ }
+ override public CellRange GetMergedRange(int row, int col, bool clip)
+ {
+ // merge cells in range (1,1)-(3,3)
+ if (row >= 1 && row <= 3 && col >= 1 && col <= 3)
+ return GetCellRange(1, 1, 3, 3);
+
+ // don't merge anything else
+ return GetCellRange(row, col);
+ }
+ }
+
+ void Initialize()
+ {
+ // enable filtering
+ _flex.AllowFiltering = true;
+
+ // set GetLocalizedString handler
+ _flex.GetLocalizedString += _flex_GetLocalizedString;
+ }
+ void _flex_GetLocalizedString(object sender, C1.Win.C1FlexGrid.GetLocalizedStringEventArgs e)
+ {
+ // customize item based on text value
+ if (e.Value == "(Select All)")
+ {
+ e.Value = "(Select Everything)";
+ }
+
+ // customize item based on component name
+ switch (e.ComponentName)
+ {
+ case "_btnApplyFilter":
+ e.Value = "OK";
+ break;
+ case "_btnClearFilter":
+ e.Value = "Reset";
+ break;
+ case "_btnCancel":
+ e.Value = "Close";
+ break;
+ }
+ }
+
+ void _flex_BeforeMouseDown(object sender, C1.Win.C1FlexGrid.BeforeMouseDownEventArgs e)
+ {
+ // start dragging when the user clicks the row headers
+ HitTestInfo hti = _flex.HitTest(e.X, e.Y);
+ if (hti.Type == HitTestTypeEnum.RowHeader)
+ {
+ e.Cancel = true; // cancel default handling
+ HandleRowDragDrop(hti.Row); // handle row drag/drop
+ }
+ }
+
+ void _flex_BeforeDoubleClick(object sender, C1.Win.C1FlexGrid.BeforeMouseDownEventArgs e)
+ {
+ // detect double-clicks on column "Customer"
+ HitTestInfo hti = _flex.HitTest(e.X, e.Y);
+ if (hti.Type == HitTestTypeEnum.Cell && _flex[hti.Column].Name == "Customer")
+ {
+ e.Cancel = true; // cancel default handling
+ ShowCustomEditDialog(hti.Row, hti.Column); // handle row drag/drop
+ }
+ }
+
+ void Form1_Load(object sender, EventArgs e)
+ {
+ // create style for tracking cell under the mouse
+ CellStyle cs = _flex.Styles.Add("track");
+ cs.BackColor = Color.Gold;
+ }
+ void _flex_MouseEnterCell(object sender, RowColEventArgs e)
+ {
+ // apply tracking style when mouse enters the cell
+ _flex.SetCellStyle(e.Row, e.Col, _flex.Styles["track"]);
+ }
+ void _flex_MouseLeaveCell(object sender, RowColEventArgs e)
+ {
+ // remove tracking style when mouse leaves the cell
+ _flex.SetCellStyle(e.Row, e.Col, (CellStyle)null);
+ }
+
+ void _flex_BeforeScroll(object sender, C1.Win.C1FlexGrid.RangeEventArgs e)
+ {
+ if (_flex.Editor != null)
+ e.Cancel = true;
+ }
+
+ _flex.ScrollOptions = ScrollFlags.DelayedScroll | ScrollFlags.ShowScrollTips;
+ void _flex_ShowScrollTip(object sender, ToolTipEventArgs e)
+ {
+ e.ToolTipText = string.Format("row {0}", e.Row);
+ }
+
+ void _flex_SetupEditor(object sender, RowColEventArgs e)
+ {
+ TextBox tb = _flex.Editor as TextBox;
+ if (tb != null)
+ {
+ if (_flex.Cols[e.Col].Name == "ID")
+ tb.MaxLength = 4;
+ else
+ tb.MaxLength = 32000;
+ }
+ }
+
+
+ void _flex_ValidateEdit(object sender, ValidateEditEventArgs e)
+ {
+ if (_flex.Cols[e.Col].Name = "Score")
+ {
+ try
+ {
+ int value = int.Parse(_flex.Editor.Text);
+ if (value >= 0 && value <= 50)
+ return; // accept edits
+ }
+ catch {}
+
+ // error or invalid range, refuse edits
+ e.Cancel = true;
+ }
+ }
+
+ void _flex_ChangeEdit(object sender, EventArgs e)
+ {
+ // get text in editor
+ string text = _flex.Editor.Text;
+
+ // show message if it's too long
+ statusStrip1.Text = text.Length > 10
+ ? "This text seems too long..."
+ : "This text looks OK...";
+ }
+
+ // create a column, assign it a name and get the new index
+ Column myCol = flex.Cols.Add();
+ myCol.Name = "address";
+ myCol.DataType = typeof(string);
+ int colIndex = myCol.Index;
+
+ // assign a value to a cell using cell coordinates:
+ flex[1, colIndex] = "555, Broadway";
+
+ // get the value using the column name
+ string address = (string)flex[1, "address"];
+ MessageBox.Show("The address is " + address);
+
+ CellRange rg = _flex.GetCellRange(3, 3, 10, 10);
+ rg.Style = _flex.Styles["MyRangeStyle"];
+
+
+ CellRange rg = _flex.GetCellRange(3, 3, 10, 10);
+ rg.Style = _flex.Styles["MyRangeStyle"];
+
+
+ CellRange rg = flex.Selection;
+ for (int r = rg.r1; r <= rg.r2; r++)
+ for (int c = rg.c1; c <= rg.c2; c++)
+ Console.WriteLine("the value at {0} {1} is {2}", r, c, flex[r, c]);
+
+ flex.SetData(1, 1, "Hello", true);
+ flex[1, 1] = "Hello"; // same thing
+
+
+ flex.SetData(1, "ColName", "Hello", true);
+ flex[1, "ColName"] = "Hello"; // same thing
+
+
+ object foo = flex.GetData(1, 1);
+ object bar = flex[1, 1]; // same thing
+
+
+ int total = 0;
+ CellRange rg = flex.Selection;
+ for (int r = rg.r1; r <= rg.r2; r++)
+ for (int c = rg.c1; c <= rg.c2; c++)
+ total += (int)flex[r,c];
+ Console.WriteLine("The total is: {0}", total);
+
+ void _flex_BeforeMouseDown(object sender, BeforeMouseDownEventArgs e)
+ {
+ HitTestInfo hti = _flex.HitTest(e.X, e.Y);
+ Console.WriteLine("at {0},{1}: row {2} col {3} type {4}",
+ hti.X, hti.Y, hti.Row, hti.Column, hti.Type);
+ }
+
+ void UpdateGrid(C1FlexGrid flex)
+ {
+ try
+ {
+ flex.BeginUpdate(); // suspend painting to avoid flicker
+ flex.Rows.Count = 1;
+ for (int i = 1; i < 10000; i++)
+ flex.AddItem("Row " + i.ToString());
+ }
+ finally
+ {
+ flex.EndUpdate(); // always restore painting
+ }
+ }
+
+ // build clip string
+ string s = "r1 c1\tr1 c2\nr2 c1\tr2 c2";
+
+ // select a 2 x 2 range and apply clip string to selection
+ flex.Select(2, 2, 4, 4);
+ flex.Clip = s;
+
+ CellRange rg = flex.GetCellRange(5, 5, 20, 8);
+ rg.Style = flex.Styles["MyStyle"];
+
+
+ // this does not compile
+ flex.GetCellRange(5, 5, 20, 8).Style = flex.Styles["MyStyle"];
+
+
+ Image img = flex.CreateImage(0,0,10,5);
+ img.Save(@"c:\temp\grid.png", System.Drawing.Imaging.ImageFormat.Png);
+
+ void _flex_SetupEditor(object sender, C1.Win.C1FlexGrid.RowColEventArgs e)
+ {
+ TextBox tb = _flex.Editor as TextBox;
+ if (tb != null)
+ {
+ tb.CharacterCasing = CharacterCasing.Upper;
+ tb.MaxLength = 12;
+ }
+ }
+
flex.ComboList = string.Empty;
+ flex.ComboList = "Item 1|Item 2|Item 3";
+ flex.ComboList = "|Item 1|Item 2|Item 3";
+ flex.ComboList = "...";
+ flex.ComboList = "|...";
+
+ void _flex_BeforeEdit(object sender, RowColEventArgs e)
+ {
+ _flex.ComboList = string.Empty;
+ if (e.Row % 2 == 0) _flex.ComboList = "...";
+ }
+
+ flex.EditMask = "(###) 000-0000 St\ate\: >LL;*";
+
+ void _flex_RowColChange(object sender, System.EventArgs e)
+ {
+ _flex.StartEditing();
+ }
+
+ void flex_SelChange(object sender, System.EventArgs e)
+ {
+ string fmt = "Count {0:0}, Sum {1:#,##0.00}, " +
+ "Avg {2:#,##0.00}, Stdev {3:#,##0.00}";
+ Console.WriteLine(fmt,
+ flex.Aggregate(AggregateEnum.Count),
+ flex.Aggregate(AggregateEnum.Sum),
+ flex.Aggregate(AggregateEnum.Average),
+ flex.Aggregate(AggregateEnum.Std));
+ }
+
+ void UpdateTotals()
+ {
+ // no repainting until we're done
+ _flex.Redraw = false;
+
+ // clear old subtotals, if any
+ _flex.Subtotal(AggregateEnum.Clear);
+
+ // sort the grid on the columns that will be grouped
+ _flex.Sort(SortFlags.Ascending, 0, 3);
+
+ // show outline tree on column 0
+ _flex.Tree.Column = 0;
+
+ // get a grand total (use -1 instead of column index)
+ _flex.Subtotal(AggregateEnum.Sum, -1, -1, 3, "Grand Total");
+
+ // total on column 0 (initially Product)
+ _flex.Subtotal(AggregateEnum.Sum, 0, 0, 3);
+
+ // total on column 1 (initially Region)
+ _flex.Subtotal(AggregateEnum.Sum, 1, 1, 3);
+
+ // show outline level 1
+ _flex.Tree.Show(1);
+
+ // restore painting
+ _flex.Redraw = true;
+ }
+ void _flex_AfterDragColumn(object sender, C1.Win.C1FlexGrid.DragRowColEventArgs e)
+ {
+ UpdateTotals(); // user moved a column, update totals
+ }
+
+
+ flex.Subtotal(AggregateEnum.Clear); // clear all subtotals
+
+ // suspend painting to improve performance
+ bool redraw = flex.Redraw;
+ flex.Redraw = false;
+
+ // append 100 rows, using tabs as separators
+ flex.ClipSeparators = "\t\n";
+ for (int i = 0; i < 100; i++)
+ flex.AddItem("\tcol1\tcol2\tcol3");
+
+ // add 100 rows at the top, using pipes as separators
+ flex.ClipSeparators = "|;";
+ for (int i = 0; i < 100; i++)
+ flex.AddItem("|col1|col2|col3", 0);
+
+ // append 100 rows at the bottom, using an object array
+ object[] items = { "col1", "col2", "col3" };
+ for (int i = 0; i < 100; i++)
+ flex.AddItem(items, flex.Rows.Count, flex.Cols.Fixed);
+
+ // restore painting
+ flex.Redraw = redraw;
+
+ // clear tabControl
+ tabControl.TabPages.Clear();
+
+ // load sheet names
+ string fileName = "c:\book1.xls";
+ string[] sheets = _flexGrid.LoadExcelSheetNames(fileName);
+
+ // load each sheet
+ foreach (string sheetName in sheets)
+ {
+ // create a new grid for this sheet
+ C1FlexGrid flex = new C1FlexGrid();
+ flex.Dock = DockStyle.Fill;
+
+ // load sheet into new grid
+ flex.LoadExcel(fileName, sheetName);
+
+ // add grid to the tabControl
+ TabPage page = new TabPage();
+ page.Controls.Add(flex);
+ page.Text = sheetName;
+ tabControl.TabPages.Add(page);
+ }
+
+ flex.AllowAddNew = true;
+ flex.Rows.Count = 10;
+ Console.WriteLine("Row count is {0}.", _flex.Rows.Count);
+ Row count is 11.
+
+
+ flex.Glyphs[GlyphEnum.Ascending] = imgAscending;
+ flex.Glyphs[GlyphEnum.Descending] = imgDescending;
+
+ // use case-insensitive comparer
+ flex.CustomComparer = new CaseInsensitiveComparer();
+
+ // add groups ignoring case
+ flex.Subtotal(AggregateEnum.Sum, 0, groupOn, totalOn);
+
+ // restore default (case-sensitive) comparer
+ flex.CustomComparer = null;
+
+ // with the ComboBoxEditor property:
+ Console.WriteLine("The current combo index is {0}",
+ _flex.ComboBoxEditor.SelectedIndex);
+
+ // without the ComboBoxEditor property:
+ ComboBox cb = _flex.Editor as ComboBox;
+ int index = (cb != null) ? cb.SelectedIndex : -1;
+ Console.WriteLine("The current combo index is {0}",
+ index);
+
+ // save a grid into am Xml file
+ flex.WriteXml(fileName);
+
+ The code below saves two grids into an Xml file, then reads them back in reverse order:
+
+ // prepare XmlTextWriter
+ XmlTextWriter w = new XmlTextWriter(fileName, new UTF8Encoding(false));
+ w.Formatting = Formatting.Indented;
+ w.WriteStartDocument();
+ w.WriteStartElement("Grids");
+
+ // save first grid
+ w.WriteStartElement(c1FlexGrid1.Name);
+ c1FlexGrid1.WriteXml(w);
+ w.WriteEndElement();
+
+ // save second grid
+ w.WriteStartElement(c1FlexGrid2.Name);
+ c1FlexGrid2.WriteXml(w);
+ w.WriteEndElement();
+
+ // close document
+ w.WriteEndElement();
+ w.Close();
+
+ // load document from file
+ XmlDocument doc = new XmlDocument();
+ doc.Load(fileName);
+ XmlNode n = doc.SelectSingleNode("Grids");
+
+ // load grids in reverse order
+ c1FlexGrid2.ReadXml(n.ChildNodes[0]);
+ c1FlexGrid1.ReadXml(n.ChildNodes[1]);
+
+ flex.Cols["CheckBoxes"].DataType = typeof(bool);
+ flex.Cols["yesNo"].DataType = typeof(bool);
+ flex.Cols["yesNo"].Format := "Yes;No";
+
+
+ flex.SetCellCheck(3, 3, CheckEnum.Unchecked) // Boolean;
+ flex.SetCellCheck(4, 3, CheckEnum.TSUnchecked) // tri-state;
+
+
+ // C#
+ SortFlags order = SortFlags.Ascending | SortFlags.IgnoreCase;
+ _flex.Sort(order, col1, col2);
+
+ ' VB
+ Dim order As SortFlags = SortFlags.Ascending Or SortFlags.IgnoreCase
+ _flex.Sort(order, col1, col2)
+
+ // create a style
+ CellStyle cs = _flex.Styles.Add("red");
+ cs.BackColor = Color.Red;
+
+ // create a cell range and assign it a style
+ CellRange rg = _flex.GetCellRange(1, 1, 5, 5);
+ rg.Style = cs;
+
+ // create a cell range
+ CellRange rg = _flex.GetCellRange(1, 1, 5, 5);
+
+ // make sure range is red
+ rg.StyleNew.BackColor = Color.Red;
+
+ // create style used to display low-stock items
+ CellStyle cs = _flex.Styles.Add("Critical");
+ cs.BackColor = Color.Red;
+
+ private void _flex_OwnerDrawCell(object sender, C1.Win.C1FlexGrid.OwnerDrawCellEventArgs e)
+ {
+ // ignore fixed cells
+ if (e.Row < _flex.Rows.Fixed || e.Col < _flex.Cols.Fixed)
+ return;
+
+ // apply custom style if reorder level is critical
+ if (_flex.Cols[e.Col].Name == "UnitsInStock")
+ {
+ // change the style by applying the "Critical" style to the Style parameter
+ // (do not change the e.Style.BackColor property directly since that would
+ // affect other cells that use this style)
+ if ((short)_flex[e.Row, "UnitsInStock"] < (short)_flex[e.Row, "ReorderLevel"])
+ e.Style = _flex.Styles["Critical"];
+ }
+ }
+
+ Form dlg = _flex.PrintParameters.PrintPreviewDialog as Form;
+ dlg.Text = "Custom Caption";
+ dlg.StartPosition = FormStartPosition.Manual;
+ dlg.WindowState = FormWindowState.Maximized;
+ _flex.PrintGrid("test", PrintGridFlags.ShowPreviewDialog);
+
+ _flex.Header = "\t\tPage {0} of {1}";
+ _flex.HeaderFont = new Font("Tahoma", 10);
+ _flex.PrintGrid("Header");
+
+ // print two grids into an existing PrintDocument
+ private void button1_Click(object sender, EventArgs e)
+ {
+ using (var dlg = new PrintPreviewDialog())
+ {
+ dlg.Document = this.printDocument1;
+ dlg.ShowDialog(this);
+ }
+ }
+
+ // event handlers for the PrintDocument object on the form
+ PrintDocumentGridRenderer _g1, _g2;
+ void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
+ {
+ // create and configure grid renderer for the first grid
+ _g1 = new PrintDocumentGridRenderer(c1FlexGrid1);
+ _g1.Options = PrintGridFlags.FitToPageWidth | PrintGridFlags.ExtendLastCol;
+
+ // create and configure grid renderer for the second grid
+ _g2 = new PrintDocumentGridRenderer(c1FlexGrid2);
+ _g2.Options = PrintGridFlags.FitToPageWidth | PrintGridFlags.ExtendLastCol;
+ }
+ void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
+ {
+ // render first grid
+ if (_g1.CurrentPage < _g1.PageCount)
+ {
+ _g1.PrintPage(e);
+ e.HasMorePages = true;
+ }
+
+ // render second grid
+ else if (_g2.CurrentPage < _g2.PageCount)
+ {
+ _g2.PrintPage(e);
+ e.HasMorePages = _g2.CurrentPage < _g2.PageCount;
+ }
+ }
+
+ // get the style associated with column 1 (create a new one if necessary)
+ CellStyle cs = _flex.Cols[1].StyleNew.BackColor;
+
+ // set the new style's back color to red
+ cs.BackColor = Color.Red;
+
+ // create C1DateEdit control (included with C1Input)
+ C1DateEdit dateEdit = new C1DateEdit();
+
+ // use the new control as an editor for a grid column
+ _flex.Cols[1].DataType = typeof(DateTime);
+ _flex.Cols[1].Editor = c1DateEdit;
+
+
+ // initialize "ShipRegion" column filter to show only two values: "AK" and "CA"
+ var col = _flex.Cols["ShipRegion"];
+ col.AllowFiltering = AllowFiltering.ByValue;
+ var vf = col.Filter as ValueFilter;
+ vf.ShowValues = new object[] { "AK", "CA" };
+
+ // initialize "UnitPrice" column filter to show only values greater than $30
+ col = _flex.Cols["UnitPrice"];
+ col.AllowFiltering = AllowFiltering.ByCondition;
+ var cf = col.Filter as ConditionFilter;
+ cf.Condition1.Operator = ConditionOperator.GreaterThan;
+ cf.Condition1.Parameter = 30;
+
+ // apply both column filters to the data
+ _flex.ApplyFilters();
+
+ // delete all selected rows
+ foreach (Row r in _flex.Rows.Selected)
+ {
+ _flex.Rows.Remove(r);
+ }
+
+
+ int columnIndex = _flex.Cols.IndexOf("total");
+ _flex.AutoSizeCol(columnIndex);
+
+ int columnIndex = _flex.Cols.IndexOf("total");
+ _flex.AutoSizeCol(columnIndex);
+
+ // s1, s2, and s3 are all references to the grid's Normal style:
+ CellStyle s1 = _flex.Styles[CellStyleEnum.Normal];
+ CellStyle s2 = _flex.Styles["Normal"];
+ CellStyle s3 = _flex.Styles.Normal;
+
+ // create style with red background
+ CellStyle cs = _flex.Styles.Add("red");
+ Style.BackColor = Color.Red;
+
+ // create style with green background
+ cs = _flex.Styles.Add("green");
+ Style.BackColor = Color.Green;
+
+ // create style with bold font
+ cs = _flex.Styles.Add("bold");
+ Style.Font = new Font("Tahoma", 8, FontStyle.Bold);
+
+ // assign red style to a column
+ _flex.Cols[3].Style = _flex.Styles["red"];
+
+ // assign green style to a row
+ _flex.Rows[3].Style = _flex.Styles["green"];
+
+ // assign bold style to a cell range
+ CellRange rg = _flex.GetCellRange(2, 2, 4, 4);
+ rg.Style = _flex.Styles["bold"];
+
+ // create a new style
+ CellStyle cs = _flex.Styles.Add("newStyle");
+
+ // set data type, alignment
+ cs.DataType = typeof(int);
+ cs.TextAlign = TextAlignEnum.CenterCenter;
+
+ // copy remaining elements from "Fixed" style
+ cs.MergeWith(_flex.Styles.Fixed);
+
+ // assign new style to grid column
+ _flex.Cols[col].Style = cs;
+
+ // create style with custom font and back color
+ CellStyle cs = _flex.Styles.Add("s1");
+ cs.Font = new Font("Arial", 12, FontStyle.Bold);
+ cs.BackColor = Color.Beige;
+
+ // save style definition into a string
+ string styleDef = cs.BuildString();
+
+ // use string to initialize another style
+ CellStyle csNew = _flex.Styles.Add("s2");
+ csNew.ParseString(styleDef);
+
+ // compare styles
+ Debug.Assert(csNew.Font.Equals(cs.Font));
+ Debug.Assert(csNew.BackColor.Equals(cs.BackColor));
+
+ // build compact and a long style definition strings
+ string s1 = _flex.Styles.Fixed.BuildString();
+ string s2 = _flex.Styles.Fixed.BuildString(StyleElementFlags.All);
+
+ // show both style definitions
+ Console.WriteLine("{0}: {1}", s1.Length, s1);
+ Console.WriteLine("{0}: {1}", s2.Length, s2);
+
+ // bind grids together
+ _flexRight.DataSource = _flexLeft;
+ _flexLeft.ScrollBars = ScrollBars.Horizontal;
+
+ // synchronize vertical scrolling
+ // (this handles the AfterScroll event for both grids)
+ void flex_AfterScroll(object sender, C1.Win.C1FlexGrid.RangeEventArgs e)
+ {
+ // update sender grid (could be _flexLeft or _flexRight)
+ C1FlexGrid.C1FlexGrid src = ((C1FlexGrid)sender);
+ src.Update();
+
+ // get new vertical position from sender grid
+ int y = src.ScrollPosition.Y;
+
+ // apply new vertical position to the other grid
+ if (src.Equals == _flexLeft)
+ {
+ _flexRight.ScrollPosition = new Point(_flexRight.ScrollPosition.X, y);
+ }
+ else
+ {
+ _flexLeft.ScrollPosition = new Point(_flexLeft.ScrollPosition.X, y);
+ }
+ }
+
+ // create string-based MultiColumnDictionary and assign it to column
+ // note: this will automatically generate keys of type 'int' for each item,
+ // the key values will be stored in the grid.
+ string text = "Row1, Col1\tRow1, Col2|Row2, Col1\tRow2, Col3|Row2, Col1\tRow3, Col2";
+ MultiColumnDictionary map = new MultiColumnDictionary(text, 0, true);
+ _flex.Cols[1].DataMap = map;
+
+
+ // create data-based MultiColumnDictionary and assign it to column
+ // notes: the list will automatically be updated is the data source changes.
+ DataTable dt = GetDataTable("employees");
+ string[] columnNames = new string[] { "FirstName", "LastName", "Country" };
+ MultiColumnDictionary map = new MultiColumnDictionary(dt, "EmployeeID", columnNames, 1);
+ _flex.Cols[2].DataMap = map;
+
+
+ [LicenseProvider(typeof(LicenseProvider))]
+ public class MyGrid : C1FlexGrid
+ {
+ // implementation
+ }
+
+
+ flex.AllowMerging = AllowMergingEnum.Free;
+ flex.Cols[1].AllowMerging = true; // merge values in column 1
+
+ private void _flex_SelChange(object sender, System.EventArgs e)
+ {
+ CellRange rg = this._flex.GetMergedRange(_flex.Row, _flex.Col, false);
+ if (!rg.IsSingleCell)
+ {
+ Console.WriteLine("selection is merged: {0},{1}-{2},{3}",
+ rg.TopRow, rg.LeftCol, rg.BottomRow, rg.RightCol);
+ }
+ }
+
+ The code below shows how you can override the
+ public class CustomMerge : C1FlexGrid
+ {
+ public CustomMerge()
+ {
+ // allow free merging by default
+ AllowMerging = AllowMergingEnum.Free;
+ for (int r = 0; r < Rows.Count; r++) Rows[r].AllowMerging = true;
+ for (int c = 0; c < Cols.Count; c++) Cols[c].AllowMerging = true;
+ }
+ override public CellRange GetMergedRange(int row, int col, bool clip)
+ {
+ // merge cells in range (1,1)-(3,3)
+ if (row >= 1 && row <= 3 && col >= 1 && col <= 3)
+ return GetCellRange(1, 1, 3, 3);
+
+ // don't merge anything else
+ return GetCellRange(row, col);
+ }
+ }
+
+ void Initialize()
+ {
+ // enable filtering
+ _flex.AllowFiltering = true;
+
+ // set GetLocalizedString handler
+ _flex.GetLocalizedString += _flex_GetLocalizedString;
+ }
+ void _flex_GetLocalizedString(object sender, C1.Win.C1FlexGrid.GetLocalizedStringEventArgs e)
+ {
+ // customize item based on text value
+ if (e.Value == "(Select All)")
+ {
+ e.Value = "(Select Everything)";
+ }
+
+ // customize item based on component name
+ switch (e.ComponentName)
+ {
+ case "_btnApplyFilter":
+ e.Value = "OK";
+ break;
+ case "_btnClearFilter":
+ e.Value = "Reset";
+ break;
+ case "_btnCancel":
+ e.Value = "Close";
+ break;
+ }
+ }
+
+ void _flex_BeforeMouseDown(object sender, C1.Win.C1FlexGrid.BeforeMouseDownEventArgs e)
+ {
+ // start dragging when the user clicks the row headers
+ HitTestInfo hti = _flex.HitTest(e.X, e.Y);
+ if (hti.Type == HitTestTypeEnum.RowHeader)
+ {
+ e.Cancel = true; // cancel default handling
+ HandleRowDragDrop(hti.Row); // handle row drag/drop
+ }
+ }
+
+ void _flex_BeforeDoubleClick(object sender, C1.Win.C1FlexGrid.BeforeMouseDownEventArgs e)
+ {
+ // detect double-clicks on column "Customer"
+ HitTestInfo hti = _flex.HitTest(e.X, e.Y);
+ if (hti.Type == HitTestTypeEnum.Cell && _flex[hti.Column].Name == "Customer")
+ {
+ e.Cancel = true; // cancel default handling
+ ShowCustomEditDialog(hti.Row, hti.Column); // handle row drag/drop
+ }
+ }
+
+ void Form1_Load(object sender, EventArgs e)
+ {
+ // create style for tracking cell under the mouse
+ CellStyle cs = _flex.Styles.Add("track");
+ cs.BackColor = Color.Gold;
+ }
+ void _flex_MouseEnterCell(object sender, RowColEventArgs e)
+ {
+ // apply tracking style when mouse enters the cell
+ _flex.SetCellStyle(e.Row, e.Col, _flex.Styles["track"]);
+ }
+ void _flex_MouseLeaveCell(object sender, RowColEventArgs e)
+ {
+ // remove tracking style when mouse leaves the cell
+ _flex.SetCellStyle(e.Row, e.Col, (CellStyle)null);
+ }
+
+ void _flex_BeforeScroll(object sender, C1.Win.C1FlexGrid.RangeEventArgs e)
+ {
+ if (_flex.Editor != null)
+ e.Cancel = true;
+ }
+
+ _flex.ScrollOptions = ScrollFlags.DelayedScroll | ScrollFlags.ShowScrollTips;
+ void _flex_ShowScrollTip(object sender, ToolTipEventArgs e)
+ {
+ e.ToolTipText = string.Format("row {0}", e.Row);
+ }
+
+ void _flex_SetupEditor(object sender, RowColEventArgs e)
+ {
+ TextBox tb = _flex.Editor as TextBox;
+ if (tb != null)
+ {
+ if (_flex.Cols[e.Col].Name == "ID")
+ tb.MaxLength = 4;
+ else
+ tb.MaxLength = 32000;
+ }
+ }
+
+
+ void _flex_ValidateEdit(object sender, ValidateEditEventArgs e)
+ {
+ if (_flex.Cols[e.Col].Name = "Score")
+ {
+ try
+ {
+ int value = int.Parse(_flex.Editor.Text);
+ if (value >= 0 && value <= 50)
+ return; // accept edits
+ }
+ catch {}
+
+ // error or invalid range, refuse edits
+ e.Cancel = true;
+ }
+ }
+
+ void _flex_ChangeEdit(object sender, EventArgs e)
+ {
+ // get text in editor
+ string text = _flex.Editor.Text;
+
+ // show message if it's too long
+ statusStrip1.Text = text.Length > 10
+ ? "This text seems too long..."
+ : "This text looks OK...";
+ }
+
+ // create a column, assign it a name and get the new index
+ Column myCol = flex.Cols.Add();
+ myCol.Name = "address";
+ myCol.DataType = typeof(string);
+ int colIndex = myCol.Index;
+
+ // assign a value to a cell using cell coordinates:
+ flex[1, colIndex] = "555, Broadway";
+
+ // get the value using the column name
+ string address = (string)flex[1, "address"];
+ MessageBox.Show("The address is " + address);
+
+ CellRange rg = _flex.GetCellRange(3, 3, 10, 10);
+ rg.Style = _flex.Styles["MyRangeStyle"];
+
+
+ CellRange rg = _flex.GetCellRange(3, 3, 10, 10);
+ rg.Style = _flex.Styles["MyRangeStyle"];
+
+
+ CellRange rg = flex.Selection;
+ for (int r = rg.r1; r <= rg.r2; r++)
+ for (int c = rg.c1; c <= rg.c2; c++)
+ Console.WriteLine("the value at {0} {1} is {2}", r, c, flex[r, c]);
+
+ flex.SetData(1, 1, "Hello", true);
+ flex[1, 1] = "Hello"; // same thing
+
+
+ flex.SetData(1, "ColName", "Hello", true);
+ flex[1, "ColName"] = "Hello"; // same thing
+
+
+ object foo = flex.GetData(1, 1);
+ object bar = flex[1, 1]; // same thing
+
+
+ int total = 0;
+ CellRange rg = flex.Selection;
+ for (int r = rg.r1; r <= rg.r2; r++)
+ for (int c = rg.c1; c <= rg.c2; c++)
+ total += (int)flex[r,c];
+ Console.WriteLine("The total is: {0}", total);
+
+ void _flex_BeforeMouseDown(object sender, BeforeMouseDownEventArgs e)
+ {
+ HitTestInfo hti = _flex.HitTest(e.X, e.Y);
+ Console.WriteLine("at {0},{1}: row {2} col {3} type {4}",
+ hti.X, hti.Y, hti.Row, hti.Column, hti.Type);
+ }
+
+ void UpdateGrid(C1FlexGrid flex)
+ {
+ try
+ {
+ flex.BeginUpdate(); // suspend painting to avoid flicker
+ flex.Rows.Count = 1;
+ for (int i = 1; i < 10000; i++)
+ flex.AddItem("Row " + i.ToString());
+ }
+ finally
+ {
+ flex.EndUpdate(); // always restore painting
+ }
+ }
+
+ // build clip string
+ string s = "r1 c1\tr1 c2\nr2 c1\tr2 c2";
+
+ // select a 2 x 2 range and apply clip string to selection
+ flex.Select(2, 2, 4, 4);
+ flex.Clip = s;
+
+ CellRange rg = flex.GetCellRange(5, 5, 20, 8);
+ rg.Style = flex.Styles["MyStyle"];
+
+
+ // this does not compile
+ flex.GetCellRange(5, 5, 20, 8).Style = flex.Styles["MyStyle"];
+
+
+ Image img = flex.CreateImage(0,0,10,5);
+ img.Save(@"c:\temp\grid.png", System.Drawing.Imaging.ImageFormat.Png);
+
+ void _flex_SetupEditor(object sender, C1.Win.C1FlexGrid.RowColEventArgs e)
+ {
+ TextBox tb = _flex.Editor as TextBox;
+ if (tb != null)
+ {
+ tb.CharacterCasing = CharacterCasing.Upper;
+ tb.MaxLength = 12;
+ }
+ }
+
flex.ComboList = string.Empty;
+ flex.ComboList = "Item 1|Item 2|Item 3";
+ flex.ComboList = "|Item 1|Item 2|Item 3";
+ flex.ComboList = "...";
+ flex.ComboList = "|...";
+
+ void _flex_BeforeEdit(object sender, RowColEventArgs e)
+ {
+ _flex.ComboList = string.Empty;
+ if (e.Row % 2 == 0) _flex.ComboList = "...";
+ }
+
+ flex.EditMask = "(###) 000-0000 St\ate\: >LL;*";
+
+ void _flex_RowColChange(object sender, System.EventArgs e)
+ {
+ _flex.StartEditing();
+ }
+
+ void flex_SelChange(object sender, System.EventArgs e)
+ {
+ string fmt = "Count {0:0}, Sum {1:#,##0.00}, " +
+ "Avg {2:#,##0.00}, Stdev {3:#,##0.00}";
+ Console.WriteLine(fmt,
+ flex.Aggregate(AggregateEnum.Count),
+ flex.Aggregate(AggregateEnum.Sum),
+ flex.Aggregate(AggregateEnum.Average),
+ flex.Aggregate(AggregateEnum.Std));
+ }
+
+ void UpdateTotals()
+ {
+ // no repainting until we're done
+ _flex.Redraw = false;
+
+ // clear old subtotals, if any
+ _flex.Subtotal(AggregateEnum.Clear);
+
+ // sort the grid on the columns that will be grouped
+ _flex.Sort(SortFlags.Ascending, 0, 3);
+
+ // show outline tree on column 0
+ _flex.Tree.Column = 0;
+
+ // get a grand total (use -1 instead of column index)
+ _flex.Subtotal(AggregateEnum.Sum, -1, -1, 3, "Grand Total");
+
+ // total on column 0 (initially Product)
+ _flex.Subtotal(AggregateEnum.Sum, 0, 0, 3);
+
+ // total on column 1 (initially Region)
+ _flex.Subtotal(AggregateEnum.Sum, 1, 1, 3);
+
+ // show outline level 1
+ _flex.Tree.Show(1);
+
+ // restore painting
+ _flex.Redraw = true;
+ }
+ void _flex_AfterDragColumn(object sender, C1.Win.C1FlexGrid.DragRowColEventArgs e)
+ {
+ UpdateTotals(); // user moved a column, update totals
+ }
+
+
+ flex.Subtotal(AggregateEnum.Clear); // clear all subtotals
+
+ // suspend painting to improve performance
+ bool redraw = flex.Redraw;
+ flex.Redraw = false;
+
+ // append 100 rows, using tabs as separators
+ flex.ClipSeparators = "\t\n";
+ for (int i = 0; i < 100; i++)
+ flex.AddItem("\tcol1\tcol2\tcol3");
+
+ // add 100 rows at the top, using pipes as separators
+ flex.ClipSeparators = "|;";
+ for (int i = 0; i < 100; i++)
+ flex.AddItem("|col1|col2|col3", 0);
+
+ // append 100 rows at the bottom, using an object array
+ object[] items = { "col1", "col2", "col3" };
+ for (int i = 0; i < 100; i++)
+ flex.AddItem(items, flex.Rows.Count, flex.Cols.Fixed);
+
+ // restore painting
+ flex.Redraw = redraw;
+
+ // clear tabControl
+ tabControl.TabPages.Clear();
+
+ // load sheet names
+ string fileName = "c:\book1.xls";
+ string[] sheets = _flexGrid.LoadExcelSheetNames(fileName);
+
+ // load each sheet
+ foreach (string sheetName in sheets)
+ {
+ // create a new grid for this sheet
+ C1FlexGrid flex = new C1FlexGrid();
+ flex.Dock = DockStyle.Fill;
+
+ // load sheet into new grid
+ flex.LoadExcel(fileName, sheetName);
+
+ // add grid to the tabControl
+ TabPage page = new TabPage();
+ page.Controls.Add(flex);
+ page.Text = sheetName;
+ tabControl.TabPages.Add(page);
+ }
+
+ flex.AllowAddNew = true;
+ flex.Rows.Count = 10;
+ Console.WriteLine("Row count is {0}.", _flex.Rows.Count);
+ Row count is 11.
+
+
+ flex.Glyphs[GlyphEnum.Ascending] = imgAscending;
+ flex.Glyphs[GlyphEnum.Descending] = imgDescending;
+
+ // use case-insensitive comparer
+ flex.CustomComparer = new CaseInsensitiveComparer();
+
+ // add groups ignoring case
+ flex.Subtotal(AggregateEnum.Sum, 0, groupOn, totalOn);
+
+ // restore default (case-sensitive) comparer
+ flex.CustomComparer = null;
+
+ // with the ComboBoxEditor property:
+ Console.WriteLine("The current combo index is {0}",
+ _flex.ComboBoxEditor.SelectedIndex);
+
+ // without the ComboBoxEditor property:
+ ComboBox cb = _flex.Editor as ComboBox;
+ int index = (cb != null) ? cb.SelectedIndex : -1;
+ Console.WriteLine("The current combo index is {0}",
+ index);
+
+ // save a grid into am Xml file
+ flex.WriteXml(fileName);
+
+ The code below saves two grids into an Xml file, then reads them back in reverse order:
+
+ // prepare XmlTextWriter
+ XmlTextWriter w = new XmlTextWriter(fileName, new UTF8Encoding(false));
+ w.Formatting = Formatting.Indented;
+ w.WriteStartDocument();
+ w.WriteStartElement("Grids");
+
+ // save first grid
+ w.WriteStartElement(c1FlexGrid1.Name);
+ c1FlexGrid1.WriteXml(w);
+ w.WriteEndElement();
+
+ // save second grid
+ w.WriteStartElement(c1FlexGrid2.Name);
+ c1FlexGrid2.WriteXml(w);
+ w.WriteEndElement();
+
+ // close document
+ w.WriteEndElement();
+ w.Close();
+
+ // load document from file
+ XmlDocument doc = new XmlDocument();
+ doc.Load(fileName);
+ XmlNode n = doc.SelectSingleNode("Grids");
+
+ // load grids in reverse order
+ c1FlexGrid2.ReadXml(n.ChildNodes[0]);
+ c1FlexGrid1.ReadXml(n.ChildNodes[1]);
+
+ flex.Cols["CheckBoxes"].DataType = typeof(bool);
+ flex.Cols["yesNo"].DataType = typeof(bool);
+ flex.Cols["yesNo"].Format := "Yes;No";
+
+
+ flex.SetCellCheck(3, 3, CheckEnum.Unchecked) // Boolean;
+ flex.SetCellCheck(4, 3, CheckEnum.TSUnchecked) // tri-state;
+
+
+ // C#
+ SortFlags order = SortFlags.Ascending | SortFlags.IgnoreCase;
+ _flex.Sort(order, col1, col2);
+
+ ' VB
+ Dim order As SortFlags = SortFlags.Ascending Or SortFlags.IgnoreCase
+ _flex.Sort(order, col1, col2)
+
+ // create a style
+ CellStyle cs = _flex.Styles.Add("red");
+ cs.BackColor = Color.Red;
+
+ // create a cell range and assign it a style
+ CellRange rg = _flex.GetCellRange(1, 1, 5, 5);
+ rg.Style = cs;
+
+ // create a cell range
+ CellRange rg = _flex.GetCellRange(1, 1, 5, 5);
+
+ // make sure range is red
+ rg.StyleNew.BackColor = Color.Red;
+
+ // create style used to display low-stock items
+ CellStyle cs = _flex.Styles.Add("Critical");
+ cs.BackColor = Color.Red;
+
+ private void _flex_OwnerDrawCell(object sender, C1.Win.C1FlexGrid.OwnerDrawCellEventArgs e)
+ {
+ // ignore fixed cells
+ if (e.Row < _flex.Rows.Fixed || e.Col < _flex.Cols.Fixed)
+ return;
+
+ // apply custom style if reorder level is critical
+ if (_flex.Cols[e.Col].Name == "UnitsInStock")
+ {
+ // change the style by applying the "Critical" style to the Style parameter
+ // (do not change the e.Style.BackColor property directly since that would
+ // affect other cells that use this style)
+ if ((short)_flex[e.Row, "UnitsInStock"] < (short)_flex[e.Row, "ReorderLevel"])
+ e.Style = _flex.Styles["Critical"];
+ }
+ }
+
+ Form dlg = _flex.PrintParameters.PrintPreviewDialog as Form;
+ dlg.Text = "Custom Caption";
+ dlg.StartPosition = FormStartPosition.Manual;
+ dlg.WindowState = FormWindowState.Maximized;
+ _flex.PrintGrid("test", PrintGridFlags.ShowPreviewDialog);
+
+ _flex.Header = "\t\tPage {0} of {1}";
+ _flex.HeaderFont = new Font("Tahoma", 10);
+ _flex.PrintGrid("Header");
+
+ // print two grids into an existing PrintDocument
+ private void button1_Click(object sender, EventArgs e)
+ {
+ using (var dlg = new PrintPreviewDialog())
+ {
+ dlg.Document = this.printDocument1;
+ dlg.ShowDialog(this);
+ }
+ }
+
+ // event handlers for the PrintDocument object on the form
+ PrintDocumentGridRenderer _g1, _g2;
+ void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
+ {
+ // create and configure grid renderer for the first grid
+ _g1 = new PrintDocumentGridRenderer(c1FlexGrid1);
+ _g1.Options = PrintGridFlags.FitToPageWidth | PrintGridFlags.ExtendLastCol;
+
+ // create and configure grid renderer for the second grid
+ _g2 = new PrintDocumentGridRenderer(c1FlexGrid2);
+ _g2.Options = PrintGridFlags.FitToPageWidth | PrintGridFlags.ExtendLastCol;
+ }
+ void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
+ {
+ // render first grid
+ if (_g1.CurrentPage < _g1.PageCount)
+ {
+ _g1.PrintPage(e);
+ e.HasMorePages = true;
+ }
+
+ // render second grid
+ else if (_g2.CurrentPage < _g2.PageCount)
+ {
+ _g2.PrintPage(e);
+ e.HasMorePages = _g2.CurrentPage < _g2.PageCount;
+ }
+ }
+
+ // get the style associated with column 1 (create a new one if necessary)
+ CellStyle cs = _flex.Cols[1].StyleNew.BackColor;
+
+ // set the new style's back color to red
+ cs.BackColor = Color.Red;
+
+ // create C1DateEdit control (included with C1Input)
+ C1DateEdit dateEdit = new C1DateEdit();
+
+ // use the new control as an editor for a grid column
+ _flex.Cols[1].DataType = typeof(DateTime);
+ _flex.Cols[1].Editor = c1DateEdit;
+
+
+ // initialize "ShipRegion" column filter to show only two values: "AK" and "CA"
+ var col = _flex.Cols["ShipRegion"];
+ col.AllowFiltering = AllowFiltering.ByValue;
+ var vf = col.Filter as ValueFilter;
+ vf.ShowValues = new object[] { "AK", "CA" };
+
+ // initialize "UnitPrice" column filter to show only values greater than $30
+ col = _flex.Cols["UnitPrice"];
+ col.AllowFiltering = AllowFiltering.ByCondition;
+ var cf = col.Filter as ConditionFilter;
+ cf.Condition1.Operator = ConditionOperator.GreaterThan;
+ cf.Condition1.Parameter = 30;
+
+ // apply both column filters to the data
+ _flex.ApplyFilters();
+
+ // delete all selected rows
+ foreach (Row r in _flex.Rows.Selected)
+ {
+ _flex.Rows.Remove(r);
+ }
+
+
+ int columnIndex = _flex.Cols.IndexOf("total");
+ _flex.AutoSizeCol(columnIndex);
+
+ int columnIndex = _flex.Cols.IndexOf("total");
+ _flex.AutoSizeCol(columnIndex);
+
+ // s1, s2, and s3 are all references to the grid's Normal style:
+ CellStyle s1 = _flex.Styles[CellStyleEnum.Normal];
+ CellStyle s2 = _flex.Styles["Normal"];
+ CellStyle s3 = _flex.Styles.Normal;
+
+ // create style with red background
+ CellStyle cs = _flex.Styles.Add("red");
+ Style.BackColor = Color.Red;
+
+ // create style with green background
+ cs = _flex.Styles.Add("green");
+ Style.BackColor = Color.Green;
+
+ // create style with bold font
+ cs = _flex.Styles.Add("bold");
+ Style.Font = new Font("Tahoma", 8, FontStyle.Bold);
+
+ // assign red style to a column
+ _flex.Cols[3].Style = _flex.Styles["red"];
+
+ // assign green style to a row
+ _flex.Rows[3].Style = _flex.Styles["green"];
+
+ // assign bold style to a cell range
+ CellRange rg = _flex.GetCellRange(2, 2, 4, 4);
+ rg.Style = _flex.Styles["bold"];
+
+ // create a new style
+ CellStyle cs = _flex.Styles.Add("newStyle");
+
+ // set data type, alignment
+ cs.DataType = typeof(int);
+ cs.TextAlign = TextAlignEnum.CenterCenter;
+
+ // copy remaining elements from "Fixed" style
+ cs.MergeWith(_flex.Styles.Fixed);
+
+ // assign new style to grid column
+ _flex.Cols[col].Style = cs;
+
+ // create style with custom font and back color
+ CellStyle cs = _flex.Styles.Add("s1");
+ cs.Font = new Font("Arial", 12, FontStyle.Bold);
+ cs.BackColor = Color.Beige;
+
+ // save style definition into a string
+ string styleDef = cs.BuildString();
+
+ // use string to initialize another style
+ CellStyle csNew = _flex.Styles.Add("s2");
+ csNew.ParseString(styleDef);
+
+ // compare styles
+ Debug.Assert(csNew.Font.Equals(cs.Font));
+ Debug.Assert(csNew.BackColor.Equals(cs.BackColor));
+
+ // build compact and a long style definition strings
+ string s1 = _flex.Styles.Fixed.BuildString();
+ string s2 = _flex.Styles.Fixed.BuildString(StyleElementFlags.All);
+
+ // show both style definitions
+ Console.WriteLine("{0}: {1}", s1.Length, s1);
+ Console.WriteLine("{0}: {1}", s2.Length, s2);
+
+ // bind grids together
+ _flexRight.DataSource = _flexLeft;
+ _flexLeft.ScrollBars = ScrollBars.Horizontal;
+
+ // synchronize vertical scrolling
+ // (this handles the AfterScroll event for both grids)
+ void flex_AfterScroll(object sender, C1.Win.C1FlexGrid.RangeEventArgs e)
+ {
+ // update sender grid (could be _flexLeft or _flexRight)
+ C1FlexGrid.C1FlexGrid src = ((C1FlexGrid)sender);
+ src.Update();
+
+ // get new vertical position from sender grid
+ int y = src.ScrollPosition.Y;
+
+ // apply new vertical position to the other grid
+ if (src.Equals == _flexLeft)
+ {
+ _flexRight.ScrollPosition = new Point(_flexRight.ScrollPosition.X, y);
+ }
+ else
+ {
+ _flexLeft.ScrollPosition = new Point(_flexLeft.ScrollPosition.X, y);
+ }
+ }
+
+ // create string-based MultiColumnDictionary and assign it to column
+ // note: this will automatically generate keys of type 'int' for each item,
+ // the key values will be stored in the grid.
+ string text = "Row1, Col1\tRow1, Col2|Row2, Col1\tRow2, Col3|Row2, Col1\tRow3, Col2";
+ MultiColumnDictionary map = new MultiColumnDictionary(text, 0, true);
+ _flex.Cols[1].DataMap = map;
+
+
+ // create data-based MultiColumnDictionary and assign it to column
+ // notes: the list will automatically be updated is the data source changes.
+ DataTable dt = GetDataTable("employees");
+ string[] columnNames = new string[] { "FirstName", "LastName", "Country" };
+ MultiColumnDictionary map = new MultiColumnDictionary(dt, "EmployeeID", columnNames, 1);
+ _flex.Cols[2].DataMap = map;
+
+
+ [LicenseProvider(typeof(LicenseProvider))]
+ public class MyGrid : C1FlexGrid
+ {
+ // implementation
+ }
+
+
+ flex.AllowMerging = AllowMergingEnum.Free;
+ flex.Cols[1].AllowMerging = true; // merge values in column 1
+
+ private void _flex_SelChange(object sender, System.EventArgs e)
+ {
+ CellRange rg = this._flex.GetMergedRange(_flex.Row, _flex.Col, false);
+ if (!rg.IsSingleCell)
+ {
+ Console.WriteLine("selection is merged: {0},{1}-{2},{3}",
+ rg.TopRow, rg.LeftCol, rg.BottomRow, rg.RightCol);
+ }
+ }
+
+ The code below shows how you can override the
+ public class CustomMerge : C1FlexGrid
+ {
+ public CustomMerge()
+ {
+ // allow free merging by default
+ AllowMerging = AllowMergingEnum.Free;
+ for (int r = 0; r < Rows.Count; r++) Rows[r].AllowMerging = true;
+ for (int c = 0; c < Cols.Count; c++) Cols[c].AllowMerging = true;
+ }
+ override public CellRange GetMergedRange(int row, int col, bool clip)
+ {
+ // merge cells in range (1,1)-(3,3)
+ if (row >= 1 && row <= 3 && col >= 1 && col <= 3)
+ return GetCellRange(1, 1, 3, 3);
+
+ // don't merge anything else
+ return GetCellRange(row, col);
+ }
+ }
+
+ void Initialize()
+ {
+ // enable filtering
+ _flex.AllowFiltering = true;
+
+ // set GetLocalizedString handler
+ _flex.GetLocalizedString += _flex_GetLocalizedString;
+ }
+ void _flex_GetLocalizedString(object sender, C1.Win.C1FlexGrid.GetLocalizedStringEventArgs e)
+ {
+ // customize item based on text value
+ if (e.Value == "(Select All)")
+ {
+ e.Value = "(Select Everything)";
+ }
+
+ // customize item based on component name
+ switch (e.ComponentName)
+ {
+ case "_btnApplyFilter":
+ e.Value = "OK";
+ break;
+ case "_btnClearFilter":
+ e.Value = "Reset";
+ break;
+ case "_btnCancel":
+ e.Value = "Close";
+ break;
+ }
+ }
+
+ void _flex_BeforeMouseDown(object sender, C1.Win.C1FlexGrid.BeforeMouseDownEventArgs e)
+ {
+ // start dragging when the user clicks the row headers
+ HitTestInfo hti = _flex.HitTest(e.X, e.Y);
+ if (hti.Type == HitTestTypeEnum.RowHeader)
+ {
+ e.Cancel = true; // cancel default handling
+ HandleRowDragDrop(hti.Row); // handle row drag/drop
+ }
+ }
+
+ void _flex_BeforeDoubleClick(object sender, C1.Win.C1FlexGrid.BeforeMouseDownEventArgs e)
+ {
+ // detect double-clicks on column "Customer"
+ HitTestInfo hti = _flex.HitTest(e.X, e.Y);
+ if (hti.Type == HitTestTypeEnum.Cell && _flex[hti.Column].Name == "Customer")
+ {
+ e.Cancel = true; // cancel default handling
+ ShowCustomEditDialog(hti.Row, hti.Column); // handle row drag/drop
+ }
+ }
+
+ void Form1_Load(object sender, EventArgs e)
+ {
+ // create style for tracking cell under the mouse
+ CellStyle cs = _flex.Styles.Add("track");
+ cs.BackColor = Color.Gold;
+ }
+ void _flex_MouseEnterCell(object sender, RowColEventArgs e)
+ {
+ // apply tracking style when mouse enters the cell
+ _flex.SetCellStyle(e.Row, e.Col, _flex.Styles["track"]);
+ }
+ void _flex_MouseLeaveCell(object sender, RowColEventArgs e)
+ {
+ // remove tracking style when mouse leaves the cell
+ _flex.SetCellStyle(e.Row, e.Col, (CellStyle)null);
+ }
+
+ void _flex_BeforeScroll(object sender, C1.Win.C1FlexGrid.RangeEventArgs e)
+ {
+ if (_flex.Editor != null)
+ e.Cancel = true;
+ }
+
+ _flex.ScrollOptions = ScrollFlags.DelayedScroll | ScrollFlags.ShowScrollTips;
+ void _flex_ShowScrollTip(object sender, ToolTipEventArgs e)
+ {
+ e.ToolTipText = string.Format("row {0}", e.Row);
+ }
+
+ void _flex_SetupEditor(object sender, RowColEventArgs e)
+ {
+ TextBox tb = _flex.Editor as TextBox;
+ if (tb != null)
+ {
+ if (_flex.Cols[e.Col].Name == "ID")
+ tb.MaxLength = 4;
+ else
+ tb.MaxLength = 32000;
+ }
+ }
+
+
+ void _flex_ValidateEdit(object sender, ValidateEditEventArgs e)
+ {
+ if (_flex.Cols[e.Col].Name = "Score")
+ {
+ try
+ {
+ int value = int.Parse(_flex.Editor.Text);
+ if (value >= 0 && value <= 50)
+ return; // accept edits
+ }
+ catch {}
+
+ // error or invalid range, refuse edits
+ e.Cancel = true;
+ }
+ }
+
+ void _flex_ChangeEdit(object sender, EventArgs e)
+ {
+ // get text in editor
+ string text = _flex.Editor.Text;
+
+ // show message if it's too long
+ statusStrip1.Text = text.Length > 10
+ ? "This text seems too long..."
+ : "This text looks OK...";
+ }
+
+ // create a column, assign it a name and get the new index
+ Column myCol = flex.Cols.Add();
+ myCol.Name = "address";
+ myCol.DataType = typeof(string);
+ int colIndex = myCol.Index;
+
+ // assign a value to a cell using cell coordinates:
+ flex[1, colIndex] = "555, Broadway";
+
+ // get the value using the column name
+ string address = (string)flex[1, "address"];
+ MessageBox.Show("The address is " + address);
+
+ CellRange rg = _flex.GetCellRange(3, 3, 10, 10);
+ rg.Style = _flex.Styles["MyRangeStyle"];
+
+
+ CellRange rg = _flex.GetCellRange(3, 3, 10, 10);
+ rg.Style = _flex.Styles["MyRangeStyle"];
+
+
+ CellRange rg = flex.Selection;
+ for (int r = rg.r1; r <= rg.r2; r++)
+ for (int c = rg.c1; c <= rg.c2; c++)
+ Console.WriteLine("the value at {0} {1} is {2}", r, c, flex[r, c]);
+
+ flex.SetData(1, 1, "Hello", true);
+ flex[1, 1] = "Hello"; // same thing
+
+
+ flex.SetData(1, "ColName", "Hello", true);
+ flex[1, "ColName"] = "Hello"; // same thing
+
+
+ object foo = flex.GetData(1, 1);
+ object bar = flex[1, 1]; // same thing
+
+
+ int total = 0;
+ CellRange rg = flex.Selection;
+ for (int r = rg.r1; r <= rg.r2; r++)
+ for (int c = rg.c1; c <= rg.c2; c++)
+ total += (int)flex[r,c];
+ Console.WriteLine("The total is: {0}", total);
+
+ void _flex_BeforeMouseDown(object sender, BeforeMouseDownEventArgs e)
+ {
+ HitTestInfo hti = _flex.HitTest(e.X, e.Y);
+ Console.WriteLine("at {0},{1}: row {2} col {3} type {4}",
+ hti.X, hti.Y, hti.Row, hti.Column, hti.Type);
+ }
+
+ void UpdateGrid(C1FlexGrid flex)
+ {
+ try
+ {
+ flex.BeginUpdate(); // suspend painting to avoid flicker
+ flex.Rows.Count = 1;
+ for (int i = 1; i < 10000; i++)
+ flex.AddItem("Row " + i.ToString());
+ }
+ finally
+ {
+ flex.EndUpdate(); // always restore painting
+ }
+ }
+
+ // build clip string
+ string s = "r1 c1\tr1 c2\nr2 c1\tr2 c2";
+
+ // select a 2 x 2 range and apply clip string to selection
+ flex.Select(2, 2, 4, 4);
+ flex.Clip = s;
+
+ CellRange rg = flex.GetCellRange(5, 5, 20, 8);
+ rg.Style = flex.Styles["MyStyle"];
+
+
+ // this does not compile
+ flex.GetCellRange(5, 5, 20, 8).Style = flex.Styles["MyStyle"];
+
+
+ Image img = flex.CreateImage(0,0,10,5);
+ img.Save(@"c:\temp\grid.png", System.Drawing.Imaging.ImageFormat.Png);
+
+ void _flex_SetupEditor(object sender, C1.Win.C1FlexGrid.RowColEventArgs e)
+ {
+ TextBox tb = _flex.Editor as TextBox;
+ if (tb != null)
+ {
+ tb.CharacterCasing = CharacterCasing.Upper;
+ tb.MaxLength = 12;
+ }
+ }
+
flex.ComboList = string.Empty;
+ flex.ComboList = "Item 1|Item 2|Item 3";
+ flex.ComboList = "|Item 1|Item 2|Item 3";
+ flex.ComboList = "...";
+ flex.ComboList = "|...";
+
+ void _flex_BeforeEdit(object sender, RowColEventArgs e)
+ {
+ _flex.ComboList = string.Empty;
+ if (e.Row % 2 == 0) _flex.ComboList = "...";
+ }
+
+ flex.EditMask = "(###) 000-0000 St\ate\: >LL;*";
+
+ void _flex_RowColChange(object sender, System.EventArgs e)
+ {
+ _flex.StartEditing();
+ }
+
+ void flex_SelChange(object sender, System.EventArgs e)
+ {
+ string fmt = "Count {0:0}, Sum {1:#,##0.00}, " +
+ "Avg {2:#,##0.00}, Stdev {3:#,##0.00}";
+ Console.WriteLine(fmt,
+ flex.Aggregate(AggregateEnum.Count),
+ flex.Aggregate(AggregateEnum.Sum),
+ flex.Aggregate(AggregateEnum.Average),
+ flex.Aggregate(AggregateEnum.Std));
+ }
+
+ void UpdateTotals()
+ {
+ // no repainting until we're done
+ _flex.Redraw = false;
+
+ // clear old subtotals, if any
+ _flex.Subtotal(AggregateEnum.Clear);
+
+ // sort the grid on the columns that will be grouped
+ _flex.Sort(SortFlags.Ascending, 0, 3);
+
+ // show outline tree on column 0
+ _flex.Tree.Column = 0;
+
+ // get a grand total (use -1 instead of column index)
+ _flex.Subtotal(AggregateEnum.Sum, -1, -1, 3, "Grand Total");
+
+ // total on column 0 (initially Product)
+ _flex.Subtotal(AggregateEnum.Sum, 0, 0, 3);
+
+ // total on column 1 (initially Region)
+ _flex.Subtotal(AggregateEnum.Sum, 1, 1, 3);
+
+ // show outline level 1
+ _flex.Tree.Show(1);
+
+ // restore painting
+ _flex.Redraw = true;
+ }
+ void _flex_AfterDragColumn(object sender, C1.Win.C1FlexGrid.DragRowColEventArgs e)
+ {
+ UpdateTotals(); // user moved a column, update totals
+ }
+
+
+ flex.Subtotal(AggregateEnum.Clear); // clear all subtotals
+
+ // suspend painting to improve performance
+ bool redraw = flex.Redraw;
+ flex.Redraw = false;
+
+ // append 100 rows, using tabs as separators
+ flex.ClipSeparators = "\t\n";
+ for (int i = 0; i < 100; i++)
+ flex.AddItem("\tcol1\tcol2\tcol3");
+
+ // add 100 rows at the top, using pipes as separators
+ flex.ClipSeparators = "|;";
+ for (int i = 0; i < 100; i++)
+ flex.AddItem("|col1|col2|col3", 0);
+
+ // append 100 rows at the bottom, using an object array
+ object[] items = { "col1", "col2", "col3" };
+ for (int i = 0; i < 100; i++)
+ flex.AddItem(items, flex.Rows.Count, flex.Cols.Fixed);
+
+ // restore painting
+ flex.Redraw = redraw;
+
+ // clear tabControl
+ tabControl.TabPages.Clear();
+
+ // load sheet names
+ string fileName = "c:\book1.xls";
+ string[] sheets = _flexGrid.LoadExcelSheetNames(fileName);
+
+ // load each sheet
+ foreach (string sheetName in sheets)
+ {
+ // create a new grid for this sheet
+ C1FlexGrid flex = new C1FlexGrid();
+ flex.Dock = DockStyle.Fill;
+
+ // load sheet into new grid
+ flex.LoadExcel(fileName, sheetName);
+
+ // add grid to the tabControl
+ TabPage page = new TabPage();
+ page.Controls.Add(flex);
+ page.Text = sheetName;
+ tabControl.TabPages.Add(page);
+ }
+
+ flex.AllowAddNew = true;
+ flex.Rows.Count = 10;
+ Console.WriteLine("Row count is {0}.", _flex.Rows.Count);
+ Row count is 11.
+
+
+ flex.Glyphs[GlyphEnum.Ascending] = imgAscending;
+ flex.Glyphs[GlyphEnum.Descending] = imgDescending;
+
+ // use case-insensitive comparer
+ flex.CustomComparer = new CaseInsensitiveComparer();
+
+ // add groups ignoring case
+ flex.Subtotal(AggregateEnum.Sum, 0, groupOn, totalOn);
+
+ // restore default (case-sensitive) comparer
+ flex.CustomComparer = null;
+
+ // with the ComboBoxEditor property:
+ Console.WriteLine("The current combo index is {0}",
+ _flex.ComboBoxEditor.SelectedIndex);
+
+ // without the ComboBoxEditor property:
+ ComboBox cb = _flex.Editor as ComboBox;
+ int index = (cb != null) ? cb.SelectedIndex : -1;
+ Console.WriteLine("The current combo index is {0}",
+ index);
+
+ // save a grid into am Xml file
+ flex.WriteXml(fileName);
+
+ The code below saves two grids into an Xml file, then reads them back in reverse order:
+
+ // prepare XmlTextWriter
+ XmlTextWriter w = new XmlTextWriter(fileName, new UTF8Encoding(false));
+ w.Formatting = Formatting.Indented;
+ w.WriteStartDocument();
+ w.WriteStartElement("Grids");
+
+ // save first grid
+ w.WriteStartElement(c1FlexGrid1.Name);
+ c1FlexGrid1.WriteXml(w);
+ w.WriteEndElement();
+
+ // save second grid
+ w.WriteStartElement(c1FlexGrid2.Name);
+ c1FlexGrid2.WriteXml(w);
+ w.WriteEndElement();
+
+ // close document
+ w.WriteEndElement();
+ w.Close();
+
+ // load document from file
+ XmlDocument doc = new XmlDocument();
+ doc.Load(fileName);
+ XmlNode n = doc.SelectSingleNode("Grids");
+
+ // load grids in reverse order
+ c1FlexGrid2.ReadXml(n.ChildNodes[0]);
+ c1FlexGrid1.ReadXml(n.ChildNodes[1]);
+
+ flex.Cols["CheckBoxes"].DataType = typeof(bool);
+ flex.Cols["yesNo"].DataType = typeof(bool);
+ flex.Cols["yesNo"].Format := "Yes;No";
+
+
+ flex.SetCellCheck(3, 3, CheckEnum.Unchecked) // Boolean;
+ flex.SetCellCheck(4, 3, CheckEnum.TSUnchecked) // tri-state;
+
+
+ // C#
+ SortFlags order = SortFlags.Ascending | SortFlags.IgnoreCase;
+ _flex.Sort(order, col1, col2);
+
+ ' VB
+ Dim order As SortFlags = SortFlags.Ascending Or SortFlags.IgnoreCase
+ _flex.Sort(order, col1, col2)
+
+ // create a style
+ CellStyle cs = _flex.Styles.Add("red");
+ cs.BackColor = Color.Red;
+
+ // create a cell range and assign it a style
+ CellRange rg = _flex.GetCellRange(1, 1, 5, 5);
+ rg.Style = cs;
+
+ // create a cell range
+ CellRange rg = _flex.GetCellRange(1, 1, 5, 5);
+
+ // make sure range is red
+ rg.StyleNew.BackColor = Color.Red;
+
+ // create style used to display low-stock items
+ CellStyle cs = _flex.Styles.Add("Critical");
+ cs.BackColor = Color.Red;
+
+ private void _flex_OwnerDrawCell(object sender, C1.Win.C1FlexGrid.OwnerDrawCellEventArgs e)
+ {
+ // ignore fixed cells
+ if (e.Row < _flex.Rows.Fixed || e.Col < _flex.Cols.Fixed)
+ return;
+
+ // apply custom style if reorder level is critical
+ if (_flex.Cols[e.Col].Name == "UnitsInStock")
+ {
+ // change the style by applying the "Critical" style to the Style parameter
+ // (do not change the e.Style.BackColor property directly since that would
+ // affect other cells that use this style)
+ if ((short)_flex[e.Row, "UnitsInStock"] < (short)_flex[e.Row, "ReorderLevel"])
+ e.Style = _flex.Styles["Critical"];
+ }
+ }
+
+ Form dlg = _flex.PrintParameters.PrintPreviewDialog as Form;
+ dlg.Text = "Custom Caption";
+ dlg.StartPosition = FormStartPosition.Manual;
+ dlg.WindowState = FormWindowState.Maximized;
+ _flex.PrintGrid("test", PrintGridFlags.ShowPreviewDialog);
+
+ _flex.Header = "\t\tPage {0} of {1}";
+ _flex.HeaderFont = new Font("Tahoma", 10);
+ _flex.PrintGrid("Header");
+
+ // print two grids into an existing PrintDocument
+ private void button1_Click(object sender, EventArgs e)
+ {
+ using (var dlg = new PrintPreviewDialog())
+ {
+ dlg.Document = this.printDocument1;
+ dlg.ShowDialog(this);
+ }
+ }
+
+ // event handlers for the PrintDocument object on the form
+ PrintDocumentGridRenderer _g1, _g2;
+ void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
+ {
+ // create and configure grid renderer for the first grid
+ _g1 = new PrintDocumentGridRenderer(c1FlexGrid1);
+ _g1.Options = PrintGridFlags.FitToPageWidth | PrintGridFlags.ExtendLastCol;
+
+ // create and configure grid renderer for the second grid
+ _g2 = new PrintDocumentGridRenderer(c1FlexGrid2);
+ _g2.Options = PrintGridFlags.FitToPageWidth | PrintGridFlags.ExtendLastCol;
+ }
+ void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
+ {
+ // render first grid
+ if (_g1.CurrentPage < _g1.PageCount)
+ {
+ _g1.PrintPage(e);
+ e.HasMorePages = true;
+ }
+
+ // render second grid
+ else if (_g2.CurrentPage < _g2.PageCount)
+ {
+ _g2.PrintPage(e);
+ e.HasMorePages = _g2.CurrentPage < _g2.PageCount;
+ }
+ }
+
+ // get the style associated with column 1 (create a new one if necessary)
+ CellStyle cs = _flex.Cols[1].StyleNew.BackColor;
+
+ // set the new style's back color to red
+ cs.BackColor = Color.Red;
+
+ // create C1DateEdit control (included with C1Input)
+ C1DateEdit dateEdit = new C1DateEdit();
+
+ // use the new control as an editor for a grid column
+ _flex.Cols[1].DataType = typeof(DateTime);
+ _flex.Cols[1].Editor = c1DateEdit;
+
+
+ // initialize "ShipRegion" column filter to show only two values: "AK" and "CA"
+ var col = _flex.Cols["ShipRegion"];
+ col.AllowFiltering = AllowFiltering.ByValue;
+ var vf = col.Filter as ValueFilter;
+ vf.ShowValues = new object[] { "AK", "CA" };
+
+ // initialize "UnitPrice" column filter to show only values greater than $30
+ col = _flex.Cols["UnitPrice"];
+ col.AllowFiltering = AllowFiltering.ByCondition;
+ var cf = col.Filter as ConditionFilter;
+ cf.Condition1.Operator = ConditionOperator.GreaterThan;
+ cf.Condition1.Parameter = 30;
+
+ // apply both column filters to the data
+ _flex.ApplyFilters();
+
+ // delete all selected rows
+ foreach (Row r in _flex.Rows.Selected)
+ {
+ _flex.Rows.Remove(r);
+ }
+
+
+ int columnIndex = _flex.Cols.IndexOf("total");
+ _flex.AutoSizeCol(columnIndex);
+
+ int columnIndex = _flex.Cols.IndexOf("total");
+ _flex.AutoSizeCol(columnIndex);
+
+ // s1, s2, and s3 are all references to the grid's Normal style:
+ CellStyle s1 = _flex.Styles[CellStyleEnum.Normal];
+ CellStyle s2 = _flex.Styles["Normal"];
+ CellStyle s3 = _flex.Styles.Normal;
+
+ // create style with red background
+ CellStyle cs = _flex.Styles.Add("red");
+ Style.BackColor = Color.Red;
+
+ // create style with green background
+ cs = _flex.Styles.Add("green");
+ Style.BackColor = Color.Green;
+
+ // create style with bold font
+ cs = _flex.Styles.Add("bold");
+ Style.Font = new Font("Tahoma", 8, FontStyle.Bold);
+
+ // assign red style to a column
+ _flex.Cols[3].Style = _flex.Styles["red"];
+
+ // assign green style to a row
+ _flex.Rows[3].Style = _flex.Styles["green"];
+
+ // assign bold style to a cell range
+ CellRange rg = _flex.GetCellRange(2, 2, 4, 4);
+ rg.Style = _flex.Styles["bold"];
+
+ // create a new style
+ CellStyle cs = _flex.Styles.Add("newStyle");
+
+ // set data type, alignment
+ cs.DataType = typeof(int);
+ cs.TextAlign = TextAlignEnum.CenterCenter;
+
+ // copy remaining elements from "Fixed" style
+ cs.MergeWith(_flex.Styles.Fixed);
+
+ // assign new style to grid column
+ _flex.Cols[col].Style = cs;
+
+ // create style with custom font and back color
+ CellStyle cs = _flex.Styles.Add("s1");
+ cs.Font = new Font("Arial", 12, FontStyle.Bold);
+ cs.BackColor = Color.Beige;
+
+ // save style definition into a string
+ string styleDef = cs.BuildString();
+
+ // use string to initialize another style
+ CellStyle csNew = _flex.Styles.Add("s2");
+ csNew.ParseString(styleDef);
+
+ // compare styles
+ Debug.Assert(csNew.Font.Equals(cs.Font));
+ Debug.Assert(csNew.BackColor.Equals(cs.BackColor));
+
+ // build compact and a long style definition strings
+ string s1 = _flex.Styles.Fixed.BuildString();
+ string s2 = _flex.Styles.Fixed.BuildString(StyleElementFlags.All);
+
+ // show both style definitions
+ Console.WriteLine("{0}: {1}", s1.Length, s1);
+ Console.WriteLine("{0}: {1}", s2.Length, s2);
+
+ // bind grids together
+ _flexRight.DataSource = _flexLeft;
+ _flexLeft.ScrollBars = ScrollBars.Horizontal;
+
+ // synchronize vertical scrolling
+ // (this handles the AfterScroll event for both grids)
+ void flex_AfterScroll(object sender, C1.Win.C1FlexGrid.RangeEventArgs e)
+ {
+ // update sender grid (could be _flexLeft or _flexRight)
+ C1FlexGrid.C1FlexGrid src = ((C1FlexGrid)sender);
+ src.Update();
+
+ // get new vertical position from sender grid
+ int y = src.ScrollPosition.Y;
+
+ // apply new vertical position to the other grid
+ if (src.Equals == _flexLeft)
+ {
+ _flexRight.ScrollPosition = new Point(_flexRight.ScrollPosition.X, y);
+ }
+ else
+ {
+ _flexLeft.ScrollPosition = new Point(_flexLeft.ScrollPosition.X, y);
+ }
+ }
+
1 Then
+ sXML = sXML & " rowspan=" & Chr(34) & spanR(iRow, iCol) & Chr(34)
+ ElseIf spanC(iRow, iCol) > 1 Then
+ sXML = sXML & " colspan=" & Chr(34) & spanC(iRow, iCol) & Chr(34)
+ ElseIf Wcol(iCol) > 0 Then
+ sXML = sXML & " width=" & Chr(34) & Wcol(iCol) & Chr(34)
+ Wcol(iCol) = Wcol(iCol) * -1
+ End If
+ sXML = sXML & ">"
+
+ For I = 1 To .Range.Paragraphs.Count
+ sTemp = .Range.Paragraphs(I).Range.Text
+ sTemp = CleanText(sTemp)
+ If sTemp <> "" Then
+ sXML = sXML & " " & sTemp & " " + End If + Next I + sXML = sXML & " | "
+ End If
+ End With
+ Next iCol
+ sXML = sXML & "
+ // create string-based MultiColumnDictionary and assign it to column
+ // note: this will automatically generate keys of type 'int' for each item,
+ // the key values will be stored in the grid.
+ string text = "Row1, Col1\tRow1, Col2|Row2, Col1\tRow2, Col3|Row2, Col1\tRow3, Col2";
+ MultiColumnDictionary map = new MultiColumnDictionary(text, 0, true);
+ _flex.Cols[1].DataMap = map;
+
+
+ // create data-based MultiColumnDictionary and assign it to column
+ // notes: the list will automatically be updated is the data source changes.
+ DataTable dt = GetDataTable("employees");
+ string[] columnNames = new string[] { "FirstName", "LastName", "Country" };
+ MultiColumnDictionary map = new MultiColumnDictionary(dt, "EmployeeID", columnNames, 1);
+ _flex.Cols[2].DataMap = map;
+
+
+ [LicenseProvider(typeof(LicenseProvider))]
+ public class MyGrid : C1FlexGrid
+ {
+ // implementation
+ }
+
+
+ flex.AllowMerging = AllowMergingEnum.Free;
+ flex.Cols[1].AllowMerging = true; // merge values in column 1
+
+ private void _flex_SelChange(object sender, System.EventArgs e)
+ {
+ CellRange rg = this._flex.GetMergedRange(_flex.Row, _flex.Col, false);
+ if (!rg.IsSingleCell)
+ {
+ Console.WriteLine("selection is merged: {0},{1}-{2},{3}",
+ rg.TopRow, rg.LeftCol, rg.BottomRow, rg.RightCol);
+ }
+ }
+
+ The code below shows how you can override the
+ public class CustomMerge : C1FlexGrid
+ {
+ public CustomMerge()
+ {
+ // allow free merging by default
+ AllowMerging = AllowMergingEnum.Free;
+ for (int r = 0; r < Rows.Count; r++) Rows[r].AllowMerging = true;
+ for (int c = 0; c < Cols.Count; c++) Cols[c].AllowMerging = true;
+ }
+ override public CellRange GetMergedRange(int row, int col, bool clip)
+ {
+ // merge cells in range (1,1)-(3,3)
+ if (row >= 1 && row <= 3 && col >= 1 && col <= 3)
+ return GetCellRange(1, 1, 3, 3);
+
+ // don't merge anything else
+ return GetCellRange(row, col);
+ }
+ }
+
+ void Initialize()
+ {
+ // enable filtering
+ _flex.AllowFiltering = true;
+
+ // set GetLocalizedString handler
+ _flex.GetLocalizedString += _flex_GetLocalizedString;
+ }
+ void _flex_GetLocalizedString(object sender, C1.Win.C1FlexGrid.GetLocalizedStringEventArgs e)
+ {
+ // customize item based on text value
+ if (e.Value == "(Select All)")
+ {
+ e.Value = "(Select Everything)";
+ }
+
+ // customize item based on component name
+ switch (e.ComponentName)
+ {
+ case "_btnApplyFilter":
+ e.Value = "OK";
+ break;
+ case "_btnClearFilter":
+ e.Value = "Reset";
+ break;
+ case "_btnCancel":
+ e.Value = "Close";
+ break;
+ }
+ }
+
+ void _flex_BeforeMouseDown(object sender, C1.Win.C1FlexGrid.BeforeMouseDownEventArgs e)
+ {
+ // start dragging when the user clicks the row headers
+ HitTestInfo hti = _flex.HitTest(e.X, e.Y);
+ if (hti.Type == HitTestTypeEnum.RowHeader)
+ {
+ e.Cancel = true; // cancel default handling
+ HandleRowDragDrop(hti.Row); // handle row drag/drop
+ }
+ }
+
+ void _flex_BeforeDoubleClick(object sender, C1.Win.C1FlexGrid.BeforeMouseDownEventArgs e)
+ {
+ // detect double-clicks on column "Customer"
+ HitTestInfo hti = _flex.HitTest(e.X, e.Y);
+ if (hti.Type == HitTestTypeEnum.Cell && _flex[hti.Column].Name == "Customer")
+ {
+ e.Cancel = true; // cancel default handling
+ ShowCustomEditDialog(hti.Row, hti.Column); // handle row drag/drop
+ }
+ }
+
+ void Form1_Load(object sender, EventArgs e)
+ {
+ // create style for tracking cell under the mouse
+ CellStyle cs = _flex.Styles.Add("track");
+ cs.BackColor = Color.Gold;
+ }
+ void _flex_MouseEnterCell(object sender, RowColEventArgs e)
+ {
+ // apply tracking style when mouse enters the cell
+ _flex.SetCellStyle(e.Row, e.Col, _flex.Styles["track"]);
+ }
+ void _flex_MouseLeaveCell(object sender, RowColEventArgs e)
+ {
+ // remove tracking style when mouse leaves the cell
+ _flex.SetCellStyle(e.Row, e.Col, (CellStyle)null);
+ }
+
+ void _flex_BeforeScroll(object sender, C1.Win.C1FlexGrid.RangeEventArgs e)
+ {
+ if (_flex.Editor != null)
+ e.Cancel = true;
+ }
+
+ _flex.ScrollOptions = ScrollFlags.DelayedScroll | ScrollFlags.ShowScrollTips;
+ void _flex_ShowScrollTip(object sender, ToolTipEventArgs e)
+ {
+ e.ToolTipText = string.Format("row {0}", e.Row);
+ }
+
+ void _flex_SetupEditor(object sender, RowColEventArgs e)
+ {
+ TextBox tb = _flex.Editor as TextBox;
+ if (tb != null)
+ {
+ if (_flex.Cols[e.Col].Name == "ID")
+ tb.MaxLength = 4;
+ else
+ tb.MaxLength = 32000;
+ }
+ }
+
+
+ void _flex_ValidateEdit(object sender, ValidateEditEventArgs e)
+ {
+ if (_flex.Cols[e.Col].Name = "Score")
+ {
+ try
+ {
+ int value = int.Parse(_flex.Editor.Text);
+ if (value >= 0 && value <= 50)
+ return; // accept edits
+ }
+ catch {}
+
+ // error or invalid range, refuse edits
+ e.Cancel = true;
+ }
+ }
+
+ void _flex_ChangeEdit(object sender, EventArgs e)
+ {
+ // get text in editor
+ string text = _flex.Editor.Text;
+
+ // show message if it's too long
+ statusStrip1.Text = text.Length > 10
+ ? "This text seems too long..."
+ : "This text looks OK...";
+ }
+
+ // create a column, assign it a name and get the new index
+ Column myCol = flex.Cols.Add();
+ myCol.Name = "address";
+ myCol.DataType = typeof(string);
+ int colIndex = myCol.Index;
+
+ // assign a value to a cell using cell coordinates:
+ flex[1, colIndex] = "555, Broadway";
+
+ // get the value using the column name
+ string address = (string)flex[1, "address"];
+ MessageBox.Show("The address is " + address);
+
+ CellRange rg = _flex.GetCellRange(3, 3, 10, 10);
+ rg.Style = _flex.Styles["MyRangeStyle"];
+
+
+ CellRange rg = _flex.GetCellRange(3, 3, 10, 10);
+ rg.Style = _flex.Styles["MyRangeStyle"];
+
+
+ CellRange rg = flex.Selection;
+ for (int r = rg.r1; r <= rg.r2; r++)
+ for (int c = rg.c1; c <= rg.c2; c++)
+ Console.WriteLine("the value at {0} {1} is {2}", r, c, flex[r, c]);
+
+ flex.SetData(1, 1, "Hello", true);
+ flex[1, 1] = "Hello"; // same thing
+
+
+ flex.SetData(1, "ColName", "Hello", true);
+ flex[1, "ColName"] = "Hello"; // same thing
+
+
+ object foo = flex.GetData(1, 1);
+ object bar = flex[1, 1]; // same thing
+
+
+ int total = 0;
+ CellRange rg = flex.Selection;
+ for (int r = rg.r1; r <= rg.r2; r++)
+ for (int c = rg.c1; c <= rg.c2; c++)
+ total += (int)flex[r,c];
+ Console.WriteLine("The total is: {0}", total);
+
+ void _flex_BeforeMouseDown(object sender, BeforeMouseDownEventArgs e)
+ {
+ HitTestInfo hti = _flex.HitTest(e.X, e.Y);
+ Console.WriteLine("at {0},{1}: row {2} col {3} type {4}",
+ hti.X, hti.Y, hti.Row, hti.Column, hti.Type);
+ }
+
+ void UpdateGrid(C1FlexGrid flex)
+ {
+ try
+ {
+ flex.BeginUpdate(); // suspend painting to avoid flicker
+ flex.Rows.Count = 1;
+ for (int i = 1; i < 10000; i++)
+ flex.AddItem("Row " + i.ToString());
+ }
+ finally
+ {
+ flex.EndUpdate(); // always restore painting
+ }
+ }
+
+ // build clip string
+ string s = "r1 c1\tr1 c2\nr2 c1\tr2 c2";
+
+ // select a 2 x 2 range and apply clip string to selection
+ flex.Select(2, 2, 4, 4);
+ flex.Clip = s;
+
+ CellRange rg = flex.GetCellRange(5, 5, 20, 8);
+ rg.Style = flex.Styles["MyStyle"];
+
+
+ // this does not compile
+ flex.GetCellRange(5, 5, 20, 8).Style = flex.Styles["MyStyle"];
+
+
+ Image img = flex.CreateImage(0,0,10,5);
+ img.Save(@"c:\temp\grid.png", System.Drawing.Imaging.ImageFormat.Png);
+
+ void _flex_SetupEditor(object sender, C1.Win.C1FlexGrid.RowColEventArgs e)
+ {
+ TextBox tb = _flex.Editor as TextBox;
+ if (tb != null)
+ {
+ tb.CharacterCasing = CharacterCasing.Upper;
+ tb.MaxLength = 12;
+ }
+ }
+
flex.ComboList = string.Empty;
+ flex.ComboList = "Item 1|Item 2|Item 3";
+ flex.ComboList = "|Item 1|Item 2|Item 3";
+ flex.ComboList = "...";
+ flex.ComboList = "|...";
+
+ void _flex_BeforeEdit(object sender, RowColEventArgs e)
+ {
+ _flex.ComboList = string.Empty;
+ if (e.Row % 2 == 0) _flex.ComboList = "...";
+ }
+
+ flex.EditMask = "(###) 000-0000 St\ate\: >LL;*";
+
+ void _flex_RowColChange(object sender, System.EventArgs e)
+ {
+ _flex.StartEditing();
+ }
+
+ void flex_SelChange(object sender, System.EventArgs e)
+ {
+ string fmt = "Count {0:0}, Sum {1:#,##0.00}, " +
+ "Avg {2:#,##0.00}, Stdev {3:#,##0.00}";
+ Console.WriteLine(fmt,
+ flex.Aggregate(AggregateEnum.Count),
+ flex.Aggregate(AggregateEnum.Sum),
+ flex.Aggregate(AggregateEnum.Average),
+ flex.Aggregate(AggregateEnum.Std));
+ }
+
+ void UpdateTotals()
+ {
+ // no repainting until we're done
+ _flex.Redraw = false;
+
+ // clear old subtotals, if any
+ _flex.Subtotal(AggregateEnum.Clear);
+
+ // sort the grid on the columns that will be grouped
+ _flex.Sort(SortFlags.Ascending, 0, 3);
+
+ // show outline tree on column 0
+ _flex.Tree.Column = 0;
+
+ // get a grand total (use -1 instead of column index)
+ _flex.Subtotal(AggregateEnum.Sum, -1, -1, 3, "Grand Total");
+
+ // total on column 0 (initially Product)
+ _flex.Subtotal(AggregateEnum.Sum, 0, 0, 3);
+
+ // total on column 1 (initially Region)
+ _flex.Subtotal(AggregateEnum.Sum, 1, 1, 3);
+
+ // show outline level 1
+ _flex.Tree.Show(1);
+
+ // restore painting
+ _flex.Redraw = true;
+ }
+ void _flex_AfterDragColumn(object sender, C1.Win.C1FlexGrid.DragRowColEventArgs e)
+ {
+ UpdateTotals(); // user moved a column, update totals
+ }
+
+
+ flex.Subtotal(AggregateEnum.Clear); // clear all subtotals
+
+ // suspend painting to improve performance
+ bool redraw = flex.Redraw;
+ flex.Redraw = false;
+
+ // append 100 rows, using tabs as separators
+ flex.ClipSeparators = "\t\n";
+ for (int i = 0; i < 100; i++)
+ flex.AddItem("\tcol1\tcol2\tcol3");
+
+ // add 100 rows at the top, using pipes as separators
+ flex.ClipSeparators = "|;";
+ for (int i = 0; i < 100; i++)
+ flex.AddItem("|col1|col2|col3", 0);
+
+ // append 100 rows at the bottom, using an object array
+ object[] items = { "col1", "col2", "col3" };
+ for (int i = 0; i < 100; i++)
+ flex.AddItem(items, flex.Rows.Count, flex.Cols.Fixed);
+
+ // restore painting
+ flex.Redraw = redraw;
+
+ // clear tabControl
+ tabControl.TabPages.Clear();
+
+ // load sheet names
+ string fileName = "c:\book1.xls";
+ string[] sheets = _flexGrid.LoadExcelSheetNames(fileName);
+
+ // load each sheet
+ foreach (string sheetName in sheets)
+ {
+ // create a new grid for this sheet
+ C1FlexGrid flex = new C1FlexGrid();
+ flex.Dock = DockStyle.Fill;
+
+ // load sheet into new grid
+ flex.LoadExcel(fileName, sheetName);
+
+ // add grid to the tabControl
+ TabPage page = new TabPage();
+ page.Controls.Add(flex);
+ page.Text = sheetName;
+ tabControl.TabPages.Add(page);
+ }
+
+ flex.AllowAddNew = true;
+ flex.Rows.Count = 10;
+ Console.WriteLine("Row count is {0}.", _flex.Rows.Count);
+ Row count is 11.
+
+
+ flex.Glyphs[GlyphEnum.Ascending] = imgAscending;
+ flex.Glyphs[GlyphEnum.Descending] = imgDescending;
+
+ // use case-insensitive comparer
+ flex.CustomComparer = new CaseInsensitiveComparer();
+
+ // add groups ignoring case
+ flex.Subtotal(AggregateEnum.Sum, 0, groupOn, totalOn);
+
+ // restore default (case-sensitive) comparer
+ flex.CustomComparer = null;
+
+ // with the ComboBoxEditor property:
+ Console.WriteLine("The current combo index is {0}",
+ _flex.ComboBoxEditor.SelectedIndex);
+
+ // without the ComboBoxEditor property:
+ ComboBox cb = _flex.Editor as ComboBox;
+ int index = (cb != null) ? cb.SelectedIndex : -1;
+ Console.WriteLine("The current combo index is {0}",
+ index);
+
+ // save a grid into am Xml file
+ flex.WriteXml(fileName);
+
+ The code below saves two grids into an Xml file, then reads them back in reverse order:
+
+ // prepare XmlTextWriter
+ XmlTextWriter w = new XmlTextWriter(fileName, new UTF8Encoding(false));
+ w.Formatting = Formatting.Indented;
+ w.WriteStartDocument();
+ w.WriteStartElement("Grids");
+
+ // save first grid
+ w.WriteStartElement(c1FlexGrid1.Name);
+ c1FlexGrid1.WriteXml(w);
+ w.WriteEndElement();
+
+ // save second grid
+ w.WriteStartElement(c1FlexGrid2.Name);
+ c1FlexGrid2.WriteXml(w);
+ w.WriteEndElement();
+
+ // close document
+ w.WriteEndElement();
+ w.Close();
+
+ // load document from file
+ XmlDocument doc = new XmlDocument();
+ doc.Load(fileName);
+ XmlNode n = doc.SelectSingleNode("Grids");
+
+ // load grids in reverse order
+ c1FlexGrid2.ReadXml(n.ChildNodes[0]);
+ c1FlexGrid1.ReadXml(n.ChildNodes[1]);
+
+ flex.Cols["CheckBoxes"].DataType = typeof(bool);
+ flex.Cols["yesNo"].DataType = typeof(bool);
+ flex.Cols["yesNo"].Format := "Yes;No";
+
+
+ flex.SetCellCheck(3, 3, CheckEnum.Unchecked) // Boolean;
+ flex.SetCellCheck(4, 3, CheckEnum.TSUnchecked) // tri-state;
+
+
+ // C#
+ SortFlags order = SortFlags.Ascending | SortFlags.IgnoreCase;
+ _flex.Sort(order, col1, col2);
+
+ ' VB
+ Dim order As SortFlags = SortFlags.Ascending Or SortFlags.IgnoreCase
+ _flex.Sort(order, col1, col2)
+
+ // create a style
+ CellStyle cs = _flex.Styles.Add("red");
+ cs.BackColor = Color.Red;
+
+ // create a cell range and assign it a style
+ CellRange rg = _flex.GetCellRange(1, 1, 5, 5);
+ rg.Style = cs;
+
+ // create a cell range
+ CellRange rg = _flex.GetCellRange(1, 1, 5, 5);
+
+ // make sure range is red
+ rg.StyleNew.BackColor = Color.Red;
+
+ // create style used to display low-stock items
+ CellStyle cs = _flex.Styles.Add("Critical");
+ cs.BackColor = Color.Red;
+
+ private void _flex_OwnerDrawCell(object sender, C1.Win.C1FlexGrid.OwnerDrawCellEventArgs e)
+ {
+ // ignore fixed cells
+ if (e.Row < _flex.Rows.Fixed || e.Col < _flex.Cols.Fixed)
+ return;
+
+ // apply custom style if reorder level is critical
+ if (_flex.Cols[e.Col].Name == "UnitsInStock")
+ {
+ // change the style by applying the "Critical" style to the Style parameter
+ // (do not change the e.Style.BackColor property directly since that would
+ // affect other cells that use this style)
+ if ((short)_flex[e.Row, "UnitsInStock"] < (short)_flex[e.Row, "ReorderLevel"])
+ e.Style = _flex.Styles["Critical"];
+ }
+ }
+
+ Form dlg = _flex.PrintParameters.PrintPreviewDialog as Form;
+ dlg.Text = "Custom Caption";
+ dlg.StartPosition = FormStartPosition.Manual;
+ dlg.WindowState = FormWindowState.Maximized;
+ _flex.PrintGrid("test", PrintGridFlags.ShowPreviewDialog);
+
+ _flex.Header = "\t\tPage {0} of {1}";
+ _flex.HeaderFont = new Font("Tahoma", 10);
+ _flex.PrintGrid("Header");
+
+ // print two grids into an existing PrintDocument
+ private void button1_Click(object sender, EventArgs e)
+ {
+ using (var dlg = new PrintPreviewDialog())
+ {
+ dlg.Document = this.printDocument1;
+ dlg.ShowDialog(this);
+ }
+ }
+
+ // event handlers for the PrintDocument object on the form
+ PrintDocumentGridRenderer _g1, _g2;
+ void printDocument1_BeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
+ {
+ // create and configure grid renderer for the first grid
+ _g1 = new PrintDocumentGridRenderer(c1FlexGrid1);
+ _g1.Options = PrintGridFlags.FitToPageWidth | PrintGridFlags.ExtendLastCol;
+
+ // create and configure grid renderer for the second grid
+ _g2 = new PrintDocumentGridRenderer(c1FlexGrid2);
+ _g2.Options = PrintGridFlags.FitToPageWidth | PrintGridFlags.ExtendLastCol;
+ }
+ void printDocument1_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
+ {
+ // render first grid
+ if (_g1.CurrentPage < _g1.PageCount)
+ {
+ _g1.PrintPage(e);
+ e.HasMorePages = true;
+ }
+
+ // render second grid
+ else if (_g2.CurrentPage < _g2.PageCount)
+ {
+ _g2.PrintPage(e);
+ e.HasMorePages = _g2.CurrentPage < _g2.PageCount;
+ }
+ }
+
+ // get the style associated with column 1 (create a new one if necessary)
+ CellStyle cs = _flex.Cols[1].StyleNew.BackColor;
+
+ // set the new style's back color to red
+ cs.BackColor = Color.Red;
+
+ // create C1DateEdit control (included with C1Input)
+ C1DateEdit dateEdit = new C1DateEdit();
+
+ // use the new control as an editor for a grid column
+ _flex.Cols[1].DataType = typeof(DateTime);
+ _flex.Cols[1].Editor = c1DateEdit;
+
+
+ // initialize "ShipRegion" column filter to show only two values: "AK" and "CA"
+ var col = _flex.Cols["ShipRegion"];
+ col.AllowFiltering = AllowFiltering.ByValue;
+ var vf = col.Filter as ValueFilter;
+ vf.ShowValues = new object[] { "AK", "CA" };
+
+ // initialize "UnitPrice" column filter to show only values greater than $30
+ col = _flex.Cols["UnitPrice"];
+ col.AllowFiltering = AllowFiltering.ByCondition;
+ var cf = col.Filter as ConditionFilter;
+ cf.Condition1.Operator = ConditionOperator.GreaterThan;
+ cf.Condition1.Parameter = 30;
+
+ // apply both column filters to the data
+ _flex.ApplyFilters();
+
+ // delete all selected rows
+ foreach (Row r in _flex.Rows.Selected)
+ {
+ _flex.Rows.Remove(r);
+ }
+
+
+ int columnIndex = _flex.Cols.IndexOf("total");
+ _flex.AutoSizeCol(columnIndex);
+
+ int columnIndex = _flex.Cols.IndexOf("total");
+ _flex.AutoSizeCol(columnIndex);
+
+ // s1, s2, and s3 are all references to the grid's Normal style:
+ CellStyle s1 = _flex.Styles[CellStyleEnum.Normal];
+ CellStyle s2 = _flex.Styles["Normal"];
+ CellStyle s3 = _flex.Styles.Normal;
+
+ // create style with red background
+ CellStyle cs = _flex.Styles.Add("red");
+ Style.BackColor = Color.Red;
+
+ // create style with green background
+ cs = _flex.Styles.Add("green");
+ Style.BackColor = Color.Green;
+
+ // create style with bold font
+ cs = _flex.Styles.Add("bold");
+ Style.Font = new Font("Tahoma", 8, FontStyle.Bold);
+
+ // assign red style to a column
+ _flex.Cols[3].Style = _flex.Styles["red"];
+
+ // assign green style to a row
+ _flex.Rows[3].Style = _flex.Styles["green"];
+
+ // assign bold style to a cell range
+ CellRange rg = _flex.GetCellRange(2, 2, 4, 4);
+ rg.Style = _flex.Styles["bold"];
+
+ // create a new style
+ CellStyle cs = _flex.Styles.Add("newStyle");
+
+ // set data type, alignment
+ cs.DataType = typeof(int);
+ cs.TextAlign = TextAlignEnum.CenterCenter;
+
+ // copy remaining elements from "Fixed" style
+ cs.MergeWith(_flex.Styles.Fixed);
+
+ // assign new style to grid column
+ _flex.Cols[col].Style = cs;
+
+ // create style with custom font and back color
+ CellStyle cs = _flex.Styles.Add("s1");
+ cs.Font = new Font("Arial", 12, FontStyle.Bold);
+ cs.BackColor = Color.Beige;
+
+ // save style definition into a string
+ string styleDef = cs.BuildString();
+
+ // use string to initialize another style
+ CellStyle csNew = _flex.Styles.Add("s2");
+ csNew.ParseString(styleDef);
+
+ // compare styles
+ Debug.Assert(csNew.Font.Equals(cs.Font));
+ Debug.Assert(csNew.BackColor.Equals(cs.BackColor));
+
+ // build compact and a long style definition strings
+ string s1 = _flex.Styles.Fixed.BuildString();
+ string s2 = _flex.Styles.Fixed.BuildString(StyleElementFlags.All);
+
+ // show both style definitions
+ Console.WriteLine("{0}: {1}", s1.Length, s1);
+ Console.WriteLine("{0}: {1}", s2.Length, s2);
+
+ // bind grids together
+ _flexRight.DataSource = _flexLeft;
+ _flexLeft.ScrollBars = ScrollBars.Horizontal;
+
+ // synchronize vertical scrolling
+ // (this handles the AfterScroll event for both grids)
+ void flex_AfterScroll(object sender, C1.Win.C1FlexGrid.RangeEventArgs e)
+ {
+ // update sender grid (could be _flexLeft or _flexRight)
+ C1FlexGrid.C1FlexGrid src = ((C1FlexGrid)sender);
+ src.Update();
+
+ // get new vertical position from sender grid
+ int y = src.ScrollPosition.Y;
+
+ // apply new vertical position to the other grid
+ if (src.Equals == _flexLeft)
+ {
+ _flexRight.ScrollPosition = new Point(_flexRight.ScrollPosition.X, y);
+ }
+ else
+ {
+ _flexLeft.ScrollPosition = new Point(_flexLeft.ScrollPosition.X, y);
+ }
+ }
+