1 // Permission is hereby granted, free of charge, to any person obtaining
2 // a copy of this software and associated documentation files (the
3 // "Software"), to deal in the Software without restriction, including
4 // without limitation the rights to use, copy, modify, merge, publish,
5 // distribute, sublicense, and/or sell copies of the Software, and to
6 // permit persons to whom the Software is furnished to do so, subject to
7 // the following conditions:
9 // The above copyright notice and this permission notice shall be
10 // included in all copies or substantial portions of the Software.
12 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
13 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
14 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
15 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
16 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
17 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
18 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 // Copyright (c) 2005,2006 Novell, Inc. (http://www.novell.com)
23 // Jordi Mas i Hernandez <jordi@ximian.com>
24 // Chris Toshok <toshok@ximian.com>
29 using System.ComponentModel;
32 using System.Runtime.InteropServices;
33 using System.Collections;
36 namespace System.Windows.Forms
38 internal class DataGridRelationshipRow {
41 public DataGridRelationshipRow (DataGrid owner)
49 relation_area = Rectangle.Empty;
54 /* this needs to be a property so that the Autosize
55 * example from the Windows.Forms FAQ will work */
57 get { return height; }
59 if (height != value) {
61 owner.UpdateRowsFrom (this);
66 public bool IsSelected;
67 public bool IsExpanded;
68 public int VerticalOffset;
69 public int RelationHeight;
70 public Rectangle relation_area; /* the Y coordinate of this rectangle is updated as needed */
73 internal class DataGridDataSource
75 public DataGrid owner;
76 public CurrencyManager list_manager;
78 public string data_member;
79 public object data_source;
80 public DataGridCell current;
82 public DataGridDataSource (DataGrid owner, CurrencyManager list_manager, object data_source, string data_member, object view_data, DataGridCell current)
85 this.list_manager = list_manager;
86 this.view = view_data;
87 this.data_source = data_source;
88 this.data_member = data_member;
89 this.current = current;
92 DataGridRelationshipRow[] rows;
93 public DataGridRelationshipRow[] Rows {
98 Hashtable selected_rows;
99 public Hashtable SelectedRows {
100 get { return selected_rows; }
101 set { selected_rows = value; }
105 public int SelectionStart {
106 get { return selection_start; }
107 set { selection_start = value; }
111 [DefaultEvent("Navigate")]
112 [DefaultProperty("DataSource")]
113 [Designer("System.Windows.Forms.Design.DataGridDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")]
114 [ComplexBindingProperties ("DataSource", "DataMember")]
115 [ClassInterface (ClassInterfaceType.AutoDispatch)]
117 public class DataGrid : Control, ISupportInitialize, IDataGridEditingService
120 public enum HitTestType
132 public sealed class HitTestInfo
134 public static readonly HitTestInfo Nowhere = null;
138 DataGrid.HitTestType type;
140 #region Private Constructors
141 internal HitTestInfo () : this (-1, -1, HitTestType.None)
145 internal HitTestInfo (int row, int column, DataGrid.HitTestType type)
148 this.column = column;
154 #region Public Instance Properties
156 get { return column; }
162 public DataGrid.HitTestType Type {
165 #endregion //Public Instance Properties
167 public override bool Equals (object value)
169 if (!(value is HitTestInfo))
172 HitTestInfo obj = (HitTestInfo) value;
173 return (obj.Column == column && obj.Row == row && obj.Type ==type);
176 public override int GetHashCode ()
181 public override string ToString ()
183 return "{ " + type + "," + row + "," + column + "}";
187 #region Local Variables
188 /* cached theme defaults */
189 static readonly Color def_background_color = ThemeEngine.Current.DataGridBackgroundColor;
190 static readonly Color def_caption_backcolor = ThemeEngine.Current.DataGridCaptionBackColor;
191 static readonly Color def_caption_forecolor = ThemeEngine.Current.DataGridCaptionForeColor;
192 static readonly Color def_parent_rows_backcolor = ThemeEngine.Current.DataGridParentRowsBackColor;
193 static readonly Color def_parent_rows_forecolor = ThemeEngine.Current.DataGridParentRowsForeColor;
196 // XXX this needs addressing. Control.background_color should not be internal.
197 new Color background_color;
198 Color caption_backcolor;
199 Color caption_forecolor;
200 Color parent_rows_backcolor;
201 Color parent_rows_forecolor;
203 /* flags to determine which areas of the datagrid are shown */
204 bool caption_visible;
205 bool parent_rows_visible;
207 GridTableStylesCollection styles_collection;
208 DataGridParentRowsLabelStyle parent_rows_label_style;
209 DataGridTableStyle default_style;
210 DataGridTableStyle grid_style;
211 DataGridTableStyle current_style;
214 DataGridCell current_cell;
215 Hashtable selected_rows;
216 int selection_start; // used for range selection
218 /* layout/rendering */
219 bool allow_navigation;
220 int first_visible_row;
221 int first_visible_column;
222 int visible_row_count;
223 int visible_column_count;
227 HScrollBar horiz_scrollbar;
228 VScrollBar vert_scrollbar;
229 int horiz_pixeloffset;
231 internal Bitmap back_button_image;
232 internal Rectangle back_button_rect;
233 internal bool back_button_mouseover;
234 internal bool back_button_active;
235 internal Bitmap parent_rows_button_image;
236 internal Rectangle parent_rows_button_rect;
237 internal bool parent_rows_button_mouseover;
238 internal bool parent_rows_button_active;
243 CurrencyManager list_manager;
244 bool refetch_list_manager = true;
246 DataGridRelationshipRow[] rows;
248 /* column resize fields */
249 bool column_resize_active;
251 int resize_column_width_delta;
254 /* row resize fields */
255 bool row_resize_active;
257 int resize_row_height_delta;
260 /* used to make sure we don't endlessly recurse calling set_CurrentCell and OnListManagerPositionChanged */
261 bool from_positionchanged_handler;
264 bool cursor_in_add_row;
265 bool add_row_changed;
266 internal bool is_editing; // Current cell is edit mode
268 bool commit_row_changes = true; // Whether to commit current edit or cancel it
269 bool adding_new_row; // Used to temporary ignore the new row added by CurrencyManager.AddNew in CurrentCell
271 internal Stack data_source_stack;
272 internal Stack data_grid_table_style_stack;
273 internal Stack grid_style_stack;
275 #endregion // Local Variables
277 #region Public Constructors
280 allow_navigation = true;
281 background_color = def_background_color;
282 border_style = BorderStyle.Fixed3D;
283 caption_backcolor = def_caption_backcolor;
284 caption_forecolor = def_caption_forecolor;
285 caption_text = string.Empty;
286 caption_visible = true;
287 datamember = string.Empty;
288 parent_rows_backcolor = def_parent_rows_backcolor;
289 parent_rows_forecolor = def_parent_rows_forecolor;
290 parent_rows_visible = true;
291 current_cell = new DataGridCell ();
292 parent_rows_label_style = DataGridParentRowsLabelStyle.Both;
293 selected_rows = new Hashtable ();
294 selection_start = -1;
295 rows = new DataGridRelationshipRow [0];
297 grid_style_stack = new Stack ();
298 data_grid_table_style_stack = new Stack ();
299 default_style = new DataGridTableStyle (true);
300 grid_style = new DataGridTableStyle ();
302 styles_collection = new GridTableStylesCollection (this);
303 styles_collection.CollectionChanged += new CollectionChangeEventHandler (OnTableStylesCollectionChanged);
305 CurrentTableStyle = grid_style;
307 horiz_scrollbar = new ImplicitHScrollBar ();
308 horiz_scrollbar.Scroll += new ScrollEventHandler (GridHScrolled);
309 vert_scrollbar = new ImplicitVScrollBar ();
310 vert_scrollbar.Scroll += new ScrollEventHandler (GridVScrolled);
312 SetStyle (ControlStyles.UserMouse, true);
314 data_source_stack = new Stack ();
316 back_button_image = ResourceImageLoader.Get ("go-previous.png");
317 back_button_image.MakeTransparent (Color.Transparent);
318 parent_rows_button_image = ResourceImageLoader.Get ("go-top.png");
319 parent_rows_button_image.MakeTransparent (Color.Transparent);
322 #endregion // Public Constructor
324 #region Public Instance Properties
327 public bool AllowNavigation {
328 get { return allow_navigation; }
330 if (allow_navigation != value) {
331 allow_navigation = value;
332 OnAllowNavigationChanged (EventArgs.Empty);
338 public bool AllowSorting {
339 get { return grid_style.AllowSorting; }
340 set { grid_style.AllowSorting = value; }
343 public Color AlternatingBackColor {
344 get { return grid_style.AlternatingBackColor; }
345 set { grid_style.AlternatingBackColor = value; }
348 public override Color BackColor {
349 get { return grid_style.BackColor; }
350 set { grid_style.BackColor = value; }
353 public Color BackgroundColor {
354 get { return background_color; }
356 if (background_color != value) {
357 background_color = value;
358 OnBackgroundColorChanged (EventArgs.Empty);
365 [EditorBrowsable(EditorBrowsableState.Never)]
366 public override Image BackgroundImage {
367 get { return base.BackgroundImage; }
369 if (base.BackgroundImage == value)
372 base.BackgroundImage = value;
378 [EditorBrowsable (EditorBrowsableState.Never)]
379 public override ImageLayout BackgroundImageLayout {
380 get { return base.BackgroundImageLayout; }
381 set { base.BackgroundImageLayout = value; }
385 [DefaultValue(BorderStyle.Fixed3D)]
386 public BorderStyle BorderStyle {
387 get { return InternalBorderStyle; }
389 InternalBorderStyle = value;
390 CalcAreasAndInvalidate ();
391 OnBorderStyleChanged (EventArgs.Empty);
395 public Color CaptionBackColor {
396 get { return caption_backcolor; }
398 if (caption_backcolor != value) {
399 caption_backcolor = value;
400 InvalidateCaption ();
407 public Font CaptionFont {
409 if (caption_font == null)
410 return new Font (Font, FontStyle.Bold);
415 if (caption_font != null && caption_font.Equals (value))
418 caption_font = value;
419 CalcAreasAndInvalidate ();
423 public Color CaptionForeColor {
424 get { return caption_forecolor; }
426 if (caption_forecolor != value) {
427 caption_forecolor = value;
428 InvalidateCaption ();
435 public string CaptionText {
436 get { return caption_text; }
438 if (caption_text != value) {
439 caption_text = value;
440 InvalidateCaption ();
446 public bool CaptionVisible {
447 get { return caption_visible; }
449 if (caption_visible != value) {
451 caption_visible = value;
452 CalcAreasAndInvalidate ();
453 OnCaptionVisibleChanged (EventArgs.Empty);
459 public bool ColumnHeadersVisible {
460 get { return grid_style.ColumnHeadersVisible; }
462 if (grid_style.ColumnHeadersVisible != value) {
463 grid_style.ColumnHeadersVisible = value;
465 // UIA Framework: To keep track of header
466 OnUIAColumnHeadersVisibleChanged ();
471 bool setting_current_cell;
474 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
475 public DataGridCell CurrentCell {
476 get { return current_cell; }
478 if (setting_current_cell)
480 setting_current_cell = true;
482 if (!IsHandleCreated) {
483 setting_current_cell = false;
484 throw new Exception ("CurrentCell cannot be set at this time.");
487 /* Even if we are on the same cell, we could need to actually start edition */
488 if (current_cell.Equals (value) && is_editing) {
489 setting_current_cell = false;
493 /* make sure the new cell fits in the correct bounds for [row,column] */
494 if (ReadOnly && value.RowNumber > RowsCount - 1)
495 value.RowNumber = RowsCount - 1;
496 else if (value.RowNumber > RowsCount)
497 value.RowNumber = RowsCount;
498 if (value.ColumnNumber >= CurrentTableStyle.GridColumnStyles.Count)
499 value.ColumnNumber = CurrentTableStyle.GridColumnStyles.Count == 0 ? 0 : CurrentTableStyle.GridColumnStyles.Count - 1;
502 /* now make sure we don't go negative */
503 if (value.RowNumber < 0) value.RowNumber = 0;
504 if (value.ColumnNumber < 0) value.ColumnNumber = 0;
506 bool was_changing = is_changing;
508 add_row_changed = add_row_changed || was_changing;
511 if (value.RowNumber != current_cell.RowNumber) {
512 if (!from_positionchanged_handler) {
514 if (commit_row_changes)
515 ListManager.EndCurrentEdit ();
517 ListManager.CancelCurrentEdit ();
519 catch (Exception e) {
520 DialogResult r = MessageBox.Show (String.Format ("{0} Do you wish to correct the value?", e.Message),
521 "Error when committing the row to the original data source",
522 MessageBoxButtons.YesNo);
523 if (r == DialogResult.Yes) {
524 InvalidateRowHeader (value.RowNumber);
525 InvalidateRowHeader (current_cell.RowNumber);
526 setting_current_cell = false;
531 ListManager.CancelCurrentEdit ();
535 if (value.RowNumber == RowsCount && !ListManager.AllowNew)
539 int old_row = current_cell.RowNumber;
541 current_cell = value;
543 EnsureCellVisibility (value);
545 // by default, edition in existing rows is commited, and for new ones is discarded, unless
546 // we receive actual input data from the user
547 if (CurrentRow == RowsCount && ListManager.AllowNew) {
548 commit_row_changes = false;
549 cursor_in_add_row = true;
550 add_row_changed = false;
552 adding_new_row = true;
554 adding_new_row = false;
557 cursor_in_add_row = false;
558 commit_row_changes = true;
561 InvalidateRowHeader (old_row);
562 InvalidateRowHeader (current_cell.RowNumber);
564 list_manager.Position = current_cell.RowNumber;
566 OnCurrentCellChanged (EventArgs.Empty);
568 if (!from_positionchanged_handler)
571 setting_current_cell = false;
575 internal void EditRowChanged (DataGridColumnStyle column_style)
577 if (cursor_in_add_row) {
578 if (!commit_row_changes) { // first change in add row, time to show another row in the ui
579 commit_row_changes = true;
580 RecreateDataGridRows (true);
586 get { return current_cell.RowNumber; }
587 set { CurrentCell = new DataGridCell (value, current_cell.ColumnNumber); }
591 get { return current_cell.ColumnNumber; }
592 set { CurrentCell = new DataGridCell (current_cell.RowNumber, value); }
596 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
597 public int CurrentRowIndex {
599 if (ListManager == null)
604 set { CurrentRow = value; }
608 [EditorBrowsable(EditorBrowsableState.Never)]
609 public override Cursor Cursor {
610 get { return base.Cursor; }
611 set { base.Cursor = value; }
615 [Editor ("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
616 public string DataMember {
617 get { return datamember; }
619 if (BindingContext != null) {
620 SetDataSource (datasource, value);
623 if (list_manager != null)
626 refetch_list_manager = true;
632 [RefreshProperties(RefreshProperties.Repaint)]
633 [AttributeProvider (typeof (IListSource))]
634 public object DataSource {
635 get { return datasource; }
637 if (BindingContext != null) {
638 SetDataSource (value, ListManager == null ? datamember : string.Empty);
642 if (list_manager != null)
643 datamember = string.Empty;
645 if (list_manager != null)
647 refetch_list_manager = true;
652 protected override Size DefaultSize {
653 get { return new Size (130, 80); }
657 public int FirstVisibleColumn {
658 get { return first_visible_column; }
661 [DefaultValue(false)]
662 public bool FlatMode {
663 get { return flatmode; }
665 if (flatmode != value) {
667 OnFlatModeChanged (EventArgs.Empty);
673 public override Color ForeColor {
674 get { return grid_style.ForeColor; }
675 set { grid_style.ForeColor = value; }
678 public Color GridLineColor {
679 get { return grid_style.GridLineColor; }
681 if (value == Color.Empty)
682 throw new ArgumentException ("Color.Empty value is invalid.");
684 grid_style.GridLineColor = value;
688 [DefaultValue(DataGridLineStyle.Solid)]
689 public DataGridLineStyle GridLineStyle {
690 get { return grid_style.GridLineStyle; }
691 set { grid_style.GridLineStyle = value; }
694 public Color HeaderBackColor {
695 get { return grid_style.HeaderBackColor; }
697 if (value == Color.Empty)
698 throw new ArgumentException ("Color.Empty value is invalid.");
700 grid_style.HeaderBackColor = value;
704 public Font HeaderFont {
705 get { return grid_style.HeaderFont; }
706 set { grid_style.HeaderFont = value; }
709 public Color HeaderForeColor {
710 get { return grid_style.HeaderForeColor; }
711 set { grid_style.HeaderForeColor = value; }
714 protected ScrollBar HorizScrollBar {
715 get { return horiz_scrollbar; }
717 internal ScrollBar HScrollBar {
718 get { return horiz_scrollbar; }
721 internal int HorizPixelOffset {
722 get { return horiz_pixeloffset; }
725 internal bool IsChanging {
726 get { return is_changing; }
729 public object this [DataGridCell cell] {
730 get { return this [cell.RowNumber, cell.ColumnNumber]; }
731 set { this [cell.RowNumber, cell.ColumnNumber] = value; }
734 public object this [int rowIndex, int columnIndex] {
735 get { return CurrentTableStyle.GridColumnStyles[columnIndex].GetColumnValueAtRow (ListManager,
738 CurrentTableStyle.GridColumnStyles[columnIndex].SetColumnValueAtRow (ListManager,
741 // UIA Framework: Raising changes in datasource.
742 OnUIAGridCellChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh,
743 new DataGridCell (rowIndex,
748 public Color LinkColor {
749 get { return grid_style.LinkColor; }
750 set { grid_style.LinkColor = value; }
753 internal Font LinkFont {
754 get { return new Font (Font, FontStyle.Underline); }
758 [EditorBrowsable(EditorBrowsableState.Never)]
759 public Color LinkHoverColor {
760 get { return grid_style.LinkHoverColor; }
761 set { grid_style.LinkHoverColor = value; }
765 [EditorBrowsable(EditorBrowsableState.Advanced)]
766 protected internal CurrencyManager ListManager {
768 if (list_manager == null && refetch_list_manager) {
769 SetDataSource (datasource, datamember);
770 refetch_list_manager = false;
775 set { throw new NotSupportedException ("Operation is not supported."); }
778 public Color ParentRowsBackColor {
779 get { return parent_rows_backcolor; }
781 if (parent_rows_backcolor != value) {
782 parent_rows_backcolor = value;
783 if (parent_rows_visible) {
790 public Color ParentRowsForeColor {
791 get { return parent_rows_forecolor; }
793 if (parent_rows_forecolor != value) {
794 parent_rows_forecolor = value;
795 if (parent_rows_visible) {
802 [DefaultValue(DataGridParentRowsLabelStyle.Both)]
803 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
804 public DataGridParentRowsLabelStyle ParentRowsLabelStyle {
805 get { return parent_rows_label_style; }
807 if (parent_rows_label_style != value) {
808 parent_rows_label_style = value;
809 if (parent_rows_visible) {
813 OnParentRowsLabelStyleChanged (EventArgs.Empty);
819 public bool ParentRowsVisible {
820 get { return parent_rows_visible; }
822 if (parent_rows_visible != value) {
823 parent_rows_visible = value;
824 CalcAreasAndInvalidate ();
825 OnParentRowsVisibleChanged (EventArgs.Empty);
830 // Settting this property seems to have no effect.
832 [TypeConverter(typeof(DataGridPreferredColumnWidthTypeConverter))]
833 public int PreferredColumnWidth {
834 get { return grid_style.PreferredColumnWidth; }
835 set { grid_style.PreferredColumnWidth = value; }
838 public int PreferredRowHeight {
839 get { return grid_style.PreferredRowHeight; }
840 set { grid_style.PreferredRowHeight = value; }
843 [DefaultValue(false)]
844 public bool ReadOnly {
845 get { return _readonly; }
847 if (_readonly != value) {
849 OnReadOnlyChanged (EventArgs.Empty);
850 CalcAreasAndInvalidate ();
856 public bool RowHeadersVisible {
857 get { return grid_style.RowHeadersVisible; }
858 set { grid_style.RowHeadersVisible = value; }
862 public int RowHeaderWidth {
863 get { return grid_style.RowHeaderWidth; }
864 set { grid_style.RowHeaderWidth = value; }
867 internal DataGridRelationshipRow[] DataGridRows {
872 public Color SelectionBackColor {
873 get { return grid_style.SelectionBackColor; }
874 set { grid_style.SelectionBackColor = value; }
877 public Color SelectionForeColor {
878 get { return grid_style.SelectionForeColor; }
879 set { grid_style.SelectionForeColor = value; }
882 public override ISite Site {
883 get { return base.Site; }
884 set { base.Site = value; }
888 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
889 public GridTableStylesCollection TableStyles {
890 get { return styles_collection; }
895 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
896 [EditorBrowsable(EditorBrowsableState.Never)]
897 public override string Text {
898 get { return base.Text; }
899 set { base.Text = value; }
903 [EditorBrowsable(EditorBrowsableState.Advanced)]
904 protected ScrollBar VertScrollBar {
905 get { return vert_scrollbar; }
907 internal ScrollBar VScrollBar {
908 get { return vert_scrollbar; }
912 public int VisibleColumnCount {
913 get { return visible_column_count; }
917 public int VisibleRowCount {
918 get { return visible_row_count; }
921 #endregion // Public Instance Properties
923 #region Private Instance Properties
924 internal DataGridTableStyle CurrentTableStyle {
925 get { return current_style; }
927 if (current_style != value) {
928 if (current_style != null)
929 DisconnectTableStyleEvents ();
931 current_style = value;
933 if (current_style != null) {
934 current_style.DataGrid = this;
935 ConnectTableStyleEvents ();
937 CalcAreasAndInvalidate ();
942 internal int FirstVisibleRow {
943 get { return first_visible_row; }
946 // As opposed to VisibleRowCount, this value is the maximum
947 // *possible* number of visible rows given our area.
948 internal int MaxVisibleRowCount {
950 return cells_area.Height / RowHeight;
954 internal int RowsCount {
955 get { return ListManager != null ? ListManager.Count : 0; }
958 internal int RowHeight {
960 if (CurrentTableStyle.CurrentPreferredRowHeight > Font.Height + 3 + 1 /* line */)
961 return CurrentTableStyle.CurrentPreferredRowHeight;
963 return Font.Height + 3 + 1 /* line */;
967 internal override bool ScaleChildrenInternal {
968 get { return false; }
971 internal bool ShowEditRow {
973 if (ListManager != null && !ListManager.AllowNew)
980 internal bool ShowParentRows {
981 get { return ParentRowsVisible && data_source_stack.Count > 0; }
984 #endregion Private Instance Properties
986 #region Public Instance Methods
991 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].Abort (current_cell.RowNumber);
993 InvalidateRowHeader (current_cell.RowNumber);
997 public bool BeginEdit (DataGridColumnStyle gridColumn, int rowNumber)
1002 int column = CurrentTableStyle.GridColumnStyles.IndexOf (gridColumn);
1006 CurrentCell = new DataGridCell (rowNumber, column);
1008 /* force editing of CurrentCell if we aren't already editing */
1014 public void BeginInit ()
1018 protected virtual void CancelEditing ()
1020 if (CurrentTableStyle.GridColumnStyles.Count == 0)
1023 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].ConcedeFocus ();
1026 if (current_cell.ColumnNumber < CurrentTableStyle.GridColumnStyles.Count)
1027 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].Abort (current_cell.RowNumber);
1028 InvalidateRowHeader (current_cell.RowNumber);
1031 if (cursor_in_add_row && !is_changing) {
1032 ListManager.CancelCurrentEdit ();
1035 is_changing = false;
1039 public void Collapse (int row)
1041 if (!rows[row].IsExpanded)
1045 rows[row].IsExpanded = false;
1046 for (int i = 1; i < rows.Length - row; i ++)
1047 rows[row + i].VerticalOffset -= rows[row].RelationHeight;
1049 rows[row].height -= rows[row].RelationHeight;
1050 rows[row].RelationHeight = 0;
1051 ResumeLayout (false);
1053 /* XX need to redraw from @row down */
1054 CalcAreasAndInvalidate ();
1057 protected internal virtual void ColumnStartedEditing (Control editingControl)
1059 ColumnStartedEditing (editingControl.Bounds);
1062 protected internal virtual void ColumnStartedEditing (Rectangle bounds)
1064 bool need_invalidate = is_changing == false;
1065 // XXX calculate the row header to invalidate
1066 // instead of using CurrentRow
1069 if (cursor_in_add_row && need_invalidate)
1070 RecreateDataGridRows (true);
1072 if (need_invalidate)
1073 InvalidateRowHeader (CurrentRow);
1076 protected override AccessibleObject CreateAccessibilityInstance ()
1078 return base.CreateAccessibilityInstance ();
1081 protected virtual DataGridColumnStyle CreateGridColumn (PropertyDescriptor prop)
1083 return CreateGridColumn (prop, false);
1086 [MonoTODO ("Not implemented, will throw NotImplementedException")]
1087 protected virtual DataGridColumnStyle CreateGridColumn (PropertyDescriptor prop, bool isDefault)
1089 throw new NotImplementedException();
1092 protected override void Dispose (bool disposing)
1094 base.Dispose (disposing);
1097 public bool EndEdit (DataGridColumnStyle gridColumn, int rowNumber, bool shouldAbort)
1099 if (shouldAbort || (_readonly || gridColumn.TableStyleReadOnly || gridColumn.ReadOnly))
1100 gridColumn.Abort (rowNumber);
1102 gridColumn.Commit (ListManager, rowNumber);
1103 gridColumn.ConcedeFocus ();
1106 if (is_editing || is_changing) {
1108 is_changing = false;
1109 InvalidateRowHeader (rowNumber);
1114 public void EndInit ()
1116 if (grid_style != null)
1117 grid_style.DataGrid = this;
1120 public void Expand (int row)
1122 if (rows[row].IsExpanded)
1125 rows[row].IsExpanded = true;
1129 string[] relations = CurrentTableStyle.Relations;
1130 StringBuilder relation_builder = new StringBuilder ("");
1132 for (i = 0; i < relations.Length; i ++) {
1134 relation_builder.Append ("\n");
1136 relation_builder.Append (relations[i]);
1138 string relation_text = relation_builder.ToString ();
1140 SizeF measured_area = TextRenderer.MeasureString (relation_text, LinkFont);
1142 rows[row].relation_area = new Rectangle (cells_area.X + 1,
1143 0, /* updated as needed at the usage sites for relation_area */
1144 (int)measured_area.Width + 4,
1145 Font.Height * relations.Length);
1147 for (i = 1; i < rows.Length - row; i ++)
1148 rows[row + i].VerticalOffset += rows[row].relation_area.Height;
1149 rows[row].height += rows[row].relation_area.Height;
1150 rows[row].RelationHeight = rows[row].relation_area.Height;
1152 /* XX need to redraw from @row down */
1153 CalcAreasAndInvalidate ();
1156 public Rectangle GetCellBounds (DataGridCell dgc)
1158 return GetCellBounds (dgc.RowNumber, dgc.ColumnNumber);
1161 public Rectangle GetCellBounds (int row, int col)
1163 Rectangle bounds = new Rectangle ();
1166 bounds.Width = CurrentTableStyle.GridColumnStyles[col].Width;
1167 bounds.Height = rows[row].Height - rows[row].RelationHeight;
1168 bounds.Y = cells_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
1169 col_pixel = GetColumnStartingPixel (col);
1170 bounds.X = cells_area.X + col_pixel - horiz_pixeloffset;
1174 public Rectangle GetCurrentCellBounds ()
1176 return GetCellBounds (current_cell.RowNumber, current_cell.ColumnNumber);
1179 protected virtual string GetOutputTextDelimiter ()
1181 return string.Empty;
1184 protected virtual void GridHScrolled (object sender, ScrollEventArgs se)
1186 if (se.NewValue == horiz_pixeloffset ||
1187 se.Type == ScrollEventType.EndScroll) {
1191 ScrollToColumnInPixels (se.NewValue);
1194 protected virtual void GridVScrolled (object sender, ScrollEventArgs se)
1196 int old_first_visible_row = first_visible_row;
1197 first_visible_row = se.NewValue;
1199 if (first_visible_row == old_first_visible_row)
1202 UpdateVisibleRowCount ();
1204 if (first_visible_row == old_first_visible_row)
1207 ScrollToRow (old_first_visible_row, first_visible_row);
1210 public HitTestInfo HitTest (Point position)
1212 return HitTest (position.X, position.Y);
1215 const int RESIZE_HANDLE_HORIZ_SIZE = 5;
1216 const int RESIZE_HANDLE_VERT_SIZE = 3;
1218 // From Point to Cell
1219 public HitTestInfo HitTest (int x, int y)
1221 if (column_headers_area.Contains (x, y)) {
1222 int offset_x = x + horiz_pixeloffset;
1224 int column_under_mouse = FromPixelToColumn (offset_x, out column_x);
1226 if (column_under_mouse == -1)
1227 return new HitTestInfo (-1, -1, HitTestType.None);
1229 if ((column_x + CurrentTableStyle.GridColumnStyles[column_under_mouse].Width - offset_x < RESIZE_HANDLE_HORIZ_SIZE)
1230 && column_under_mouse < CurrentTableStyle.GridColumnStyles.Count) {
1232 return new HitTestInfo (-1, column_under_mouse, HitTestType.ColumnResize);
1235 return new HitTestInfo (-1, column_under_mouse, HitTestType.ColumnHeader);
1239 if (row_headers_area.Contains (x, y)) {
1241 int rcnt = FirstVisibleRow + VisibleRowCount;
1242 for (int r = FirstVisibleRow; r < rcnt; r++) {
1243 posy = cells_area.Y + rows[r].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
1244 if (y <= posy + rows[r].Height) {
1245 if ((posy + rows[r].Height) - y < RESIZE_HANDLE_VERT_SIZE) {
1246 return new HitTestInfo (r, -1, HitTestType.RowResize);
1249 return new HitTestInfo (r, -1, HitTestType.RowHeader);
1255 if (caption_area.Contains (x, y)) {
1256 return new HitTestInfo (-1, -1, HitTestType.Caption);
1259 if (parent_rows.Contains (x, y)) {
1260 return new HitTestInfo (-1, -1, HitTestType.ParentRows);
1263 int pos_y, pos_x, width;
1264 int rowcnt = FirstVisibleRow + VisibleRowCount;
1265 for (int row = FirstVisibleRow; row < rowcnt; row++) {
1267 pos_y = cells_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
1268 if (y <= pos_y + rows[row].Height) {
1270 int column_cnt = first_visible_column + visible_column_count;
1271 if (column_cnt > 0) {
1272 for (int column = first_visible_column; column < column_cnt; column++) {
1273 if (CurrentTableStyle.GridColumnStyles[column].bound == false)
1275 col_pixel = GetColumnStartingPixel (column);
1276 pos_x = cells_area.X + col_pixel - horiz_pixeloffset;
1277 width = CurrentTableStyle.GridColumnStyles[column].Width;
1279 if (x <= pos_x + width) { // Column found
1280 return new HitTestInfo (row, column, HitTestType.Cell);
1284 else if (CurrentTableStyle.HasRelations) {
1285 /* XXX this needs checking against MS somehow... */
1286 if (x < rows[row].relation_area.X + rows[row].relation_area.Width)
1287 return new HitTestInfo (row, 0/*XXX?*/, HitTestType.Cell);
1294 return new HitTestInfo ();
1297 public bool IsExpanded (int rowNumber)
1299 return (rows[rowNumber].IsExpanded);
1302 public bool IsSelected (int row)
1304 return rows[row].IsSelected;
1307 public void NavigateBack ()
1309 if (data_source_stack.Count == 0)
1314 DataGridDataSource source = (DataGridDataSource)data_source_stack.Pop ();
1315 CurrentTableStyle= (DataGridTableStyle)data_grid_table_style_stack.Pop ();
1316 grid_style = (DataGridTableStyle) grid_style_stack.Pop ();
1318 list_manager = source.list_manager;
1320 selected_rows = source.SelectedRows;
1321 selection_start = source.SelectionStart;
1322 SetDataSource (source.data_source, source.data_member);
1324 CurrentCell = source.current;
1327 public void NavigateTo (int rowNumber, string relationName)
1329 if (allow_navigation == false)
1334 DataGridDataSource previous_source = new DataGridDataSource (this, list_manager, datasource, datamember, list_manager.Current, CurrentCell);
1335 previous_source.Rows = rows;
1336 previous_source.SelectedRows = selected_rows;
1337 previous_source.SelectionStart = selection_start;
1339 data_source_stack.Push (previous_source);
1341 data_grid_table_style_stack.Push (CurrentTableStyle);
1342 grid_style_stack.Push (grid_style);
1343 grid_style = new DataGridTableStyle ();
1344 CurrentTableStyle = grid_style;
1347 selected_rows = new Hashtable ();
1348 selection_start = -1;
1350 DataMember = String.Format ("{0}.{1}", DataMember, relationName);
1351 OnDataSourceChanged (EventArgs.Empty);
1354 protected virtual void OnAllowNavigationChanged (EventArgs e)
1356 EventHandler eh = (EventHandler)(Events [AllowNavigationChangedEvent]);
1361 protected void OnBackButtonClicked (object sender, EventArgs e)
1363 EventHandler eh = (EventHandler)(Events [BackButtonClickEvent]);
1368 protected override void OnBackColorChanged (EventArgs e)
1370 base.OnBackColorChanged (e);
1373 protected virtual void OnBackgroundColorChanged (EventArgs e)
1375 EventHandler eh = (EventHandler)(Events [BackgroundColorChangedEvent]);
1380 protected override void OnBindingContextChanged (EventArgs e)
1382 base.OnBindingContextChanged (e);
1384 SetDataSource (datasource, datamember);
1387 protected virtual void OnBorderStyleChanged (EventArgs e)
1389 EventHandler eh = (EventHandler)(Events [BorderStyleChangedEvent]);
1394 protected virtual void OnCaptionVisibleChanged (EventArgs e)
1396 EventHandler eh = (EventHandler)(Events [CaptionVisibleChangedEvent]);
1401 protected virtual void OnCurrentCellChanged (EventArgs e)
1403 EventHandler eh = (EventHandler)(Events [CurrentCellChangedEvent]);
1408 protected virtual void OnDataSourceChanged (EventArgs e)
1410 EventHandler eh = (EventHandler)(Events [DataSourceChangedEvent]);
1415 protected override void OnEnter (EventArgs e)
1421 protected virtual void OnFlatModeChanged (EventArgs e)
1423 EventHandler eh = (EventHandler)(Events [FlatModeChangedEvent]);
1428 protected override void OnFontChanged (EventArgs e)
1431 base.OnFontChanged (e);
1434 protected override void OnForeColorChanged (EventArgs e)
1436 base.OnForeColorChanged (e);
1439 protected override void OnHandleCreated (EventArgs e)
1441 base.OnHandleCreated (e);
1442 SetDataSource (datasource, datamember);
1445 protected override void OnHandleDestroyed (EventArgs e)
1447 base.OnHandleDestroyed (e);
1450 // It seems we have repeated code with ProcessKeyPreview, specifically
1451 // the call to ProcessGridKey. In practice it seems this event is *never* fired
1452 // since the key events are handled by the current column's textbox.
1453 // We are keeping commented anyway, in case we need to actually call it.
1454 protected override void OnKeyDown (KeyEventArgs ke)
1456 base.OnKeyDown (ke);
1458 /*if (ProcessGridKey (ke) == true)
1461 // TODO: we probably don't need this check,
1462 // since current_cell wouldn't have been set
1463 // to something invalid
1464 if (CurrentTableStyle.GridColumnStyles.Count > 0) {
1465 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].OnKeyDown
1466 (ke, current_cell.RowNumber, current_cell.ColumnNumber);
1470 protected override void OnKeyPress (KeyPressEventArgs kpe)
1472 base.OnKeyPress (kpe);
1475 protected override void OnLayout (LayoutEventArgs levent)
1477 base.OnLayout (levent);
1478 CalcAreasAndInvalidate ();
1481 protected override void OnLeave (EventArgs e)
1486 if (commit_row_changes)
1487 ListManager.EndCurrentEdit ();
1489 ListManager.CancelCurrentEdit ();
1492 protected override void OnMouseDown (MouseEventArgs e)
1494 base.OnMouseDown (e);
1496 bool ctrl_pressed = ((Control.ModifierKeys & Keys.Control) != 0);
1497 bool shift_pressed = ((Control.ModifierKeys & Keys.Shift) != 0);
1499 HitTestInfo testinfo;
1500 testinfo = HitTest (e.X, e.Y);
1502 switch (testinfo.Type) {
1503 case HitTestType.Cell:
1504 if (testinfo.Row < 0 || testinfo.Column < 0)
1507 if (rows[testinfo.Row].IsExpanded) {
1508 Rectangle relation_area = rows[testinfo.Row].relation_area;
1509 relation_area.Y = rows[testinfo.Row].VerticalOffset + cells_area.Y + rows[testinfo.Row].Height - rows[testinfo.Row].RelationHeight;
1510 if (relation_area.Contains (e.X, e.Y)) {
1511 /* the click happened in the relation area, navigate to the new table */
1512 int relative = e.Y - relation_area.Y;
1513 NavigateTo (testinfo.Row, CurrentTableStyle.Relations[relative / LinkFont.Height]);
1518 DataGridCell new_cell = new DataGridCell (testinfo.Row, testinfo.Column);
1520 if ((new_cell.Equals (current_cell) == false) || (!is_editing)) {
1522 CurrentCell = new_cell;
1525 CurrentTableStyle.GridColumnStyles[testinfo.Column].OnMouseDown (e, testinfo.Row, testinfo.Column);
1530 case HitTestType.RowHeader:
1531 bool expansion_click = false;
1532 if (CurrentTableStyle.HasRelations) {
1533 if (e.X > row_headers_area.X + row_headers_area.Width / 2) {
1534 /* it's in the +/- space */
1535 if (IsExpanded (testinfo.Row))
1536 Collapse (testinfo.Row);
1538 Expand (testinfo.Row);
1540 expansion_click = true;
1545 CurrentRow = testinfo.Row;
1547 if (!ctrl_pressed && !shift_pressed && !expansion_click) {
1548 ResetSelection (); // Invalidates selected rows
1551 if ((shift_pressed || expansion_click) && selection_start != -1) {
1552 ShiftSelection (testinfo.Row);
1553 } else { // ctrl_pressed or single item
1554 selection_start = testinfo.Row;
1555 Select (testinfo.Row);
1558 OnRowHeaderClick (EventArgs.Empty);
1562 case HitTestType.ColumnHeader:
1563 if (CurrentTableStyle.GridColumnStyles.Count == 0)
1566 if (AllowSorting == false)
1569 if (ListManager.List is IBindingList == false)
1572 // Don't do any sort if we are empty, as .net does
1573 if (ListManager.Count == 0)
1576 ListSortDirection direction = ListSortDirection.Ascending;
1577 PropertyDescriptor prop = CurrentTableStyle.GridColumnStyles[testinfo.Column].PropertyDescriptor;
1578 IBindingList list = (IBindingList) ListManager.List;
1580 if (list.SortProperty != null) {
1581 CurrentTableStyle.GridColumnStyles[list.SortProperty].ArrowDrawingMode
1582 = DataGridColumnStyle.ArrowDrawing.No;
1585 if (prop == list.SortProperty && list.SortDirection == ListSortDirection.Ascending) {
1586 direction = ListSortDirection.Descending;
1589 CurrentTableStyle.GridColumnStyles[testinfo.Column].ArrowDrawingMode =
1590 direction == ListSortDirection.Ascending ?
1591 DataGridColumnStyle.ArrowDrawing.Ascending : DataGridColumnStyle.ArrowDrawing.Descending;
1593 list.ApplySort (prop, direction);
1595 if (this.is_editing)
1596 //CurrentTableStyle.GridColumnStyles[CurrentColumn].UpdateUI ();
1597 this.InvalidateColumn (CurrentTableStyle.GridColumnStyles[CurrentColumn]);
1601 case HitTestType.ColumnResize:
1602 if (e.Clicks == 2) {
1604 ColumnResize (testinfo.Column);
1606 resize_column = testinfo.Column;
1607 column_resize_active = true;
1608 resize_column_x = e.X;
1609 resize_column_width_delta = 0;
1611 DrawResizeLineVert (resize_column_x);
1615 case HitTestType.RowResize:
1616 if (e.Clicks == 2) {
1618 RowResize (testinfo.Row);
1620 resize_row = testinfo.Row;
1621 row_resize_active = true;
1623 resize_row_height_delta = 0;
1625 DrawResizeLineHoriz (resize_row_y);
1629 case HitTestType.Caption:
1630 if (back_button_rect.Contains (e.X, e.Y)) {
1631 back_button_active = true;
1632 Invalidate (back_button_rect);
1634 if (parent_rows_button_rect.Contains (e.X, e.Y)) {
1635 parent_rows_button_active = true;
1636 Invalidate (parent_rows_button_rect);
1645 protected override void OnMouseLeave (EventArgs e)
1647 base.OnMouseLeave (e);
1650 protected override void OnMouseMove (MouseEventArgs e)
1652 base.OnMouseMove (e);
1654 if (column_resize_active) {
1655 /* erase the old line */
1656 DrawResizeLineVert (resize_column_x + resize_column_width_delta);
1658 resize_column_width_delta = e.X - resize_column_x;
1660 /* draw the new line */
1661 DrawResizeLineVert (resize_column_x + resize_column_width_delta);
1664 else if (row_resize_active) {
1665 /* erase the old line */
1666 DrawResizeLineHoriz (resize_row_y + resize_row_height_delta);
1668 resize_row_height_delta = e.Y - resize_row_y;
1670 /* draw the new line */
1671 DrawResizeLineHoriz (resize_row_y + resize_row_height_delta);
1675 /* determine the cursor to use */
1676 HitTestInfo testinfo;
1677 testinfo = HitTest (e.X, e.Y);
1679 switch (testinfo.Type) {
1680 case HitTestType.ColumnResize:
1681 Cursor = Cursors.VSplit;
1683 case HitTestType.RowResize:
1684 Cursor = Cursors.HSplit;
1686 case HitTestType.Caption:
1687 Cursor = Cursors.Default;
1688 if (back_button_rect.Contains (e.X, e.Y)) {
1689 if (!back_button_mouseover)
1690 Invalidate (back_button_rect);
1691 back_button_mouseover = true;
1692 } else if (back_button_mouseover) {
1693 Invalidate (back_button_rect);
1694 back_button_mouseover = false;
1697 if (parent_rows_button_rect.Contains (e.X, e.Y)) {
1698 if (parent_rows_button_mouseover)
1699 Invalidate (parent_rows_button_rect);
1700 parent_rows_button_mouseover = true;
1701 } else if (parent_rows_button_mouseover) {
1702 Invalidate (parent_rows_button_rect);
1703 parent_rows_button_mouseover = false;
1706 case HitTestType.Cell:
1707 if (rows[testinfo.Row].IsExpanded) {
1708 Rectangle relation_area = rows[testinfo.Row].relation_area;
1709 relation_area.Y = rows[testinfo.Row].VerticalOffset + cells_area.Y + rows[testinfo.Row].Height - rows[testinfo.Row].RelationHeight;
1710 if (relation_area.Contains (e.X, e.Y)) {
1711 Cursor = Cursors.Hand;
1716 Cursor = Cursors.Default;
1718 case HitTestType.RowHeader:
1719 if (e.Button == MouseButtons.Left)
1720 ShiftSelection (testinfo.Row);
1722 Cursor = Cursors.Default;
1725 Cursor = Cursors.Default;
1731 protected override void OnMouseUp (MouseEventArgs e)
1735 if (column_resize_active) {
1736 column_resize_active = false;
1737 if (resize_column_width_delta + CurrentTableStyle.GridColumnStyles[resize_column].Width < 0)
1738 resize_column_width_delta = -CurrentTableStyle.GridColumnStyles[resize_column].Width;
1739 CurrentTableStyle.GridColumnStyles[resize_column].Width += resize_column_width_delta;
1740 width_of_all_columns += resize_column_width_delta;
1743 } else if (row_resize_active) {
1744 row_resize_active = false;
1746 if (resize_row_height_delta + rows[resize_row].Height < 0)
1747 resize_row_height_delta = -rows[resize_row].Height;
1749 rows[resize_row].height = rows[resize_row].Height + resize_row_height_delta;
1750 for (int i = resize_row + 1; i < rows.Length; i ++)
1751 rows[i].VerticalOffset += resize_row_height_delta;
1754 CalcAreasAndInvalidate ();
1755 } else if (back_button_active) {
1756 if (back_button_rect.Contains (e.X, e.Y)) {
1757 Invalidate (back_button_rect);
1759 OnBackButtonClicked (this, EventArgs.Empty);
1761 back_button_active = false;
1762 } else if (parent_rows_button_active) {
1763 if (parent_rows_button_rect.Contains (e.X, e.Y)) {
1764 Invalidate (parent_rows_button_rect);
1765 ParentRowsVisible = !ParentRowsVisible;
1766 OnShowParentDetailsButtonClicked (this, EventArgs.Empty);
1768 parent_rows_button_active = false;
1772 protected override void OnMouseWheel (MouseEventArgs e)
1774 base.OnMouseWheel (e);
1776 bool ctrl_pressed = ((Control.ModifierKeys & Keys.Control) != 0);
1779 if (ctrl_pressed) { // scroll horizontally
1780 if (!horiz_scrollbar.Visible)
1785 pixels = Math.Max (horiz_scrollbar.Minimum,
1786 horiz_scrollbar.Value - horiz_scrollbar.LargeChange);
1789 pixels = Math.Min (horiz_scrollbar.Maximum - horiz_scrollbar.LargeChange + 1,
1790 horiz_scrollbar.Value + horiz_scrollbar.LargeChange);
1793 GridHScrolled (this, new ScrollEventArgs (ScrollEventType.ThumbPosition, pixels));
1794 horiz_scrollbar.Value = pixels;
1796 if (!vert_scrollbar.Visible)
1801 pixels = Math.Max (vert_scrollbar.Minimum,
1802 vert_scrollbar.Value - vert_scrollbar.LargeChange);
1805 pixels = Math.Min (vert_scrollbar.Maximum - vert_scrollbar.LargeChange + 1,
1806 vert_scrollbar.Value + vert_scrollbar.LargeChange);
1809 GridVScrolled (this, new ScrollEventArgs (ScrollEventType.ThumbPosition, pixels));
1810 vert_scrollbar.Value = pixels;
1814 protected void OnNavigate (NavigateEventArgs e)
1816 EventHandler eh = (EventHandler)(Events [NavigateEvent]);
1821 protected override void OnPaint (PaintEventArgs pe)
1823 ThemeEngine.Current.DataGridPaint (pe, this);
1826 protected override void OnPaintBackground (PaintEventArgs ebe)
1830 protected virtual void OnParentRowsLabelStyleChanged (EventArgs e)
1832 EventHandler eh = (EventHandler)(Events [ParentRowsLabelStyleChangedEvent]);
1837 protected virtual void OnParentRowsVisibleChanged (EventArgs e)
1839 EventHandler eh = (EventHandler)(Events [ParentRowsVisibleChangedEvent]);
1844 protected virtual void OnReadOnlyChanged (EventArgs e)
1846 EventHandler eh = (EventHandler)(Events [ReadOnlyChangedEvent]);
1851 protected override void OnResize (EventArgs e)
1856 protected void OnRowHeaderClick (EventArgs e)
1858 EventHandler eh = (EventHandler)(Events [RowHeaderClickEvent]);
1863 protected void OnScroll (EventArgs e)
1865 EventHandler eh = (EventHandler)(Events [ScrollEvent]);
1870 protected void OnShowParentDetailsButtonClicked (object sender, EventArgs e)
1872 EventHandler eh = (EventHandler)(Events [ShowParentDetailsButtonClickEvent]);
1877 protected override bool ProcessDialogKey (Keys keyData)
1879 return ProcessGridKey (new KeyEventArgs (keyData));
1882 void UpdateSelectionAfterCursorMove (bool extend_selection)
1884 if (extend_selection) {
1886 ShiftSelection (CurrentRow);
1889 selection_start = CurrentRow;
1893 protected bool ProcessGridKey (KeyEventArgs ke)
1895 bool ctrl_pressed = ((ke.Modifiers & Keys.Control) != 0);
1896 //bool alt_pressed = ((ke.Modifiers & Keys.Alt) != 0);
1897 bool shift_pressed = ((ke.Modifiers & Keys.Shift) != 0);
1899 switch (ke.KeyCode) {
1906 if (cursor_in_add_row && CurrentRow > 0)
1916 CurrentTableStyle.GridColumnStyles[CurrentColumn].EnterNullValue ();
1927 if (shift_pressed) {
1928 if (CurrentColumn > 0)
1930 else if ((CurrentRow > 0) && (CurrentColumn == 0))
1931 CurrentCell = new DataGridCell (CurrentRow - 1, CurrentTableStyle.GridColumnStyles.Count - 1);
1933 if (CurrentColumn < CurrentTableStyle.GridColumnStyles.Count - 1)
1935 else if ((CurrentRow <= RowsCount) && (CurrentColumn == CurrentTableStyle.GridColumnStyles.Count - 1))
1936 CurrentCell = new DataGridCell (CurrentRow + 1, 0);
1939 UpdateSelectionAfterCursorMove (false);
1945 CurrentColumn = CurrentTableStyle.GridColumnStyles.Count - 1;
1947 if (CurrentColumn < CurrentTableStyle.GridColumnStyles.Count - 1) {
1949 } else if (CurrentRow < RowsCount - 1
1950 || (CurrentRow == RowsCount - 1
1951 && !cursor_in_add_row)) {
1952 CurrentCell = new DataGridCell (CurrentRow + 1, 0);
1956 UpdateSelectionAfterCursorMove (false);
1964 if (current_cell.ColumnNumber > 0)
1966 else if (CurrentRow > 0)
1967 CurrentCell = new DataGridCell (CurrentRow - 1, CurrentTableStyle.GridColumnStyles.Count - 1);
1970 UpdateSelectionAfterCursorMove (false);
1977 else if (CurrentRow > 0)
1980 UpdateSelectionAfterCursorMove (shift_pressed);
1986 CurrentRow = RowsCount - 1;
1987 else if (CurrentRow < RowsCount - 1)
1989 else if (CurrentRow == RowsCount - 1 && cursor_in_add_row && (add_row_changed || is_changing))
1991 else if (CurrentRow == RowsCount - 1 && !cursor_in_add_row && !shift_pressed)
1994 UpdateSelectionAfterCursorMove (shift_pressed);
1999 if (CurrentRow > VLargeChange)
2000 CurrentRow -= VLargeChange;
2004 UpdateSelectionAfterCursorMove (shift_pressed);
2009 if (CurrentRow < RowsCount - VLargeChange)
2010 CurrentRow += VLargeChange;
2012 CurrentRow = RowsCount - 1;
2014 UpdateSelectionAfterCursorMove (shift_pressed);
2020 CurrentCell = new DataGridCell (0, 0);
2024 UpdateSelectionAfterCursorMove (ctrl_pressed && shift_pressed);
2030 CurrentCell = new DataGridCell (RowsCount - 1, CurrentTableStyle.GridColumnStyles.Count - 1);
2032 CurrentColumn = CurrentTableStyle.GridColumnStyles.Count - 1;
2034 UpdateSelectionAfterCursorMove (ctrl_pressed && shift_pressed);
2041 else if (selected_rows.Keys.Count > 0) {
2042 // the removal of the items in the source will cause to
2043 // reset the selection, so we need a copy of it.
2044 int [] rows = new int [selected_rows.Keys.Count];
2045 selected_rows.Keys.CopyTo (rows, 0);
2047 // reverse order to keep index sanity
2048 int edit_row_index = ShowEditRow ? RowsCount : -1; // new cell is +1
2049 for (int i = rows.Length - 1; i >= 0; i--)
2050 if (rows [i] != edit_row_index)
2051 ListManager.RemoveAt (rows [i]);
2053 CalcAreasAndInvalidate ();
2059 return false; // message not processed
2062 protected override bool ProcessKeyPreview (ref Message m)
2064 if ((Msg) m.Msg == Msg.WM_KEYDOWN) {
2065 Keys key = (Keys) m.WParam.ToInt32 ();
2066 KeyEventArgs ke = new KeyEventArgs (key | XplatUI.State.ModifierKeys);
2067 if (ProcessGridKey (ke))
2070 // if we receive a key event, make sure that input is actually
2071 // taken into account.
2074 InvalidateRow (current_cell.RowNumber);
2079 return base.ProcessKeyPreview (ref m);
2082 protected bool ProcessTabKey (Keys keyData)
2087 public void ResetAlternatingBackColor ()
2089 grid_style.AlternatingBackColor = default_style.AlternatingBackColor;
2092 public override void ResetBackColor ()
2094 grid_style.BackColor = default_style.BackColor;
2097 public override void ResetForeColor ()
2099 grid_style.ForeColor = default_style.ForeColor;
2102 public void ResetGridLineColor ()
2104 grid_style.GridLineColor = default_style.GridLineColor;
2107 public void ResetHeaderBackColor ()
2109 grid_style.HeaderBackColor = default_style.HeaderBackColor;
2112 public void ResetHeaderFont ()
2114 grid_style.HeaderFont = null;
2117 public void ResetHeaderForeColor ()
2119 grid_style.HeaderForeColor = default_style.HeaderForeColor;
2122 public void ResetLinkColor ()
2124 grid_style.LinkColor = default_style.LinkColor;
2127 public void ResetLinkHoverColor ()
2129 grid_style.LinkHoverColor = default_style.LinkHoverColor;
2132 protected void ResetSelection ()
2134 InvalidateSelection ();
2135 selected_rows.Clear ();
2136 selection_start = -1;
2139 void InvalidateSelection ()
2141 foreach (int row in selected_rows.Keys) {
2142 rows[row].IsSelected = false;
2143 InvalidateRow (row);
2147 public void ResetSelectionBackColor ()
2149 grid_style.SelectionBackColor = default_style.SelectionBackColor;
2152 public void ResetSelectionForeColor ()
2154 grid_style.SelectionForeColor = default_style.SelectionForeColor;
2157 public void Select (int row)
2161 if (selected_rows.Count == 0)
2162 selection_start = row;
2164 // UIA Framework: To raise event only when selecting
2165 bool wasSelected = rows [row].IsSelected;
2167 selected_rows[row] = true;
2168 rows[row].IsSelected = true;
2170 InvalidateRow (row);
2174 OnUIASelectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, row));
2178 public void SetDataBinding (object dataSource, string dataMember)
2180 SetDataSource (dataSource, dataMember);
2183 protected virtual bool ShouldSerializeAlternatingBackColor ()
2185 return (grid_style.AlternatingBackColor != default_style.AlternatingBackColor);
2188 protected virtual bool ShouldSerializeBackgroundColor ()
2190 return (background_color != def_background_color);
2193 protected virtual bool ShouldSerializeCaptionBackColor ()
2195 return (caption_backcolor != def_caption_backcolor);
2198 protected virtual bool ShouldSerializeCaptionForeColor ()
2200 return caption_forecolor != def_caption_forecolor;
2203 protected virtual bool ShouldSerializeGridLineColor ()
2205 return grid_style.GridLineColor != default_style.GridLineColor;
2208 protected virtual bool ShouldSerializeHeaderBackColor ()
2210 return grid_style.HeaderBackColor != default_style.HeaderBackColor;
2213 protected bool ShouldSerializeHeaderFont ()
2215 return grid_style.HeaderFont != default_style.HeaderFont;
2218 protected virtual bool ShouldSerializeHeaderForeColor ()
2220 return grid_style.HeaderForeColor != default_style.HeaderForeColor;
2223 protected virtual bool ShouldSerializeLinkHoverColor ()
2225 return grid_style.LinkHoverColor != grid_style.LinkHoverColor;
2228 protected virtual bool ShouldSerializeParentRowsBackColor ()
2230 return parent_rows_backcolor != def_parent_rows_backcolor;
2233 protected virtual bool ShouldSerializeParentRowsForeColor ()
2235 return parent_rows_backcolor != def_parent_rows_backcolor;
2238 protected bool ShouldSerializePreferredRowHeight ()
2240 return grid_style.PreferredRowHeight != default_style.PreferredRowHeight;
2243 protected bool ShouldSerializeSelectionBackColor ()
2245 return grid_style.SelectionBackColor != default_style.SelectionBackColor;
2248 protected virtual bool ShouldSerializeSelectionForeColor ()
2250 return grid_style.SelectionForeColor != default_style.SelectionForeColor;
2253 public void SubObjectsSiteChange (bool site)
2257 public void UnSelect (int row)
2259 // UIA Framework: To raise event only when unselecting
2260 bool wasSelected = rows [row].IsSelected;
2262 rows[row].IsSelected = false;
2263 selected_rows.Remove (row);
2264 InvalidateRow (row);
2266 // UIA Framework: Raises selection event
2268 OnUIASelectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, row));
2270 #endregion // Public Instance Methods
2272 #region Private Instance Methods
2274 internal void CalcAreasAndInvalidate ()
2280 private void ConnectListManagerEvents ()
2282 list_manager.MetaDataChanged += new EventHandler (OnListManagerMetaDataChanged);
2283 list_manager.PositionChanged += new EventHandler (OnListManagerPositionChanged);
2284 list_manager.ItemChanged += new ItemChangedEventHandler (OnListManagerItemChanged);
2287 private void DisconnectListManagerEvents ()
2289 list_manager.MetaDataChanged -= new EventHandler (OnListManagerMetaDataChanged);
2290 list_manager.PositionChanged -= new EventHandler (OnListManagerPositionChanged);
2291 list_manager.ItemChanged -= new ItemChangedEventHandler (OnListManagerItemChanged);
2294 void DisconnectTableStyleEvents ()
2296 current_style.AllowSortingChanged -= new EventHandler (TableStyleChanged);
2297 current_style.AlternatingBackColorChanged -= new EventHandler (TableStyleChanged);
2298 current_style.BackColorChanged -= new EventHandler (TableStyleChanged);
2299 current_style.ColumnHeadersVisibleChanged -= new EventHandler (TableStyleChanged);
2300 current_style.ForeColorChanged -= new EventHandler (TableStyleChanged);
2301 current_style.GridLineColorChanged -= new EventHandler (TableStyleChanged);
2302 current_style.GridLineStyleChanged -= new EventHandler (TableStyleChanged);
2303 current_style.HeaderBackColorChanged -= new EventHandler (TableStyleChanged);
2304 current_style.HeaderFontChanged -= new EventHandler (TableStyleChanged);
2305 current_style.HeaderForeColorChanged -= new EventHandler (TableStyleChanged);
2306 current_style.LinkColorChanged -= new EventHandler (TableStyleChanged);
2307 current_style.LinkHoverColorChanged -= new EventHandler (TableStyleChanged);
2308 current_style.MappingNameChanged -= new EventHandler (TableStyleChanged);
2309 current_style.PreferredColumnWidthChanged -= new EventHandler (TableStyleChanged);
2310 current_style.PreferredRowHeightChanged -= new EventHandler (TableStyleChanged);
2311 current_style.ReadOnlyChanged -= new EventHandler (TableStyleChanged);
2312 current_style.RowHeadersVisibleChanged -= new EventHandler (TableStyleChanged);
2313 current_style.RowHeaderWidthChanged -= new EventHandler (TableStyleChanged);
2314 current_style.SelectionBackColorChanged -= new EventHandler (TableStyleChanged);
2315 current_style.SelectionForeColorChanged -= new EventHandler (TableStyleChanged);
2318 void ConnectTableStyleEvents ()
2320 current_style.AllowSortingChanged += new EventHandler (TableStyleChanged);
2321 current_style.AlternatingBackColorChanged += new EventHandler (TableStyleChanged);
2322 current_style.BackColorChanged += new EventHandler (TableStyleChanged);
2323 current_style.ColumnHeadersVisibleChanged += new EventHandler (TableStyleChanged);
2324 current_style.ForeColorChanged += new EventHandler (TableStyleChanged);
2325 current_style.GridLineColorChanged += new EventHandler (TableStyleChanged);
2326 current_style.GridLineStyleChanged += new EventHandler (TableStyleChanged);
2327 current_style.HeaderBackColorChanged += new EventHandler (TableStyleChanged);
2328 current_style.HeaderFontChanged += new EventHandler (TableStyleChanged);
2329 current_style.HeaderForeColorChanged += new EventHandler (TableStyleChanged);
2330 current_style.LinkColorChanged += new EventHandler (TableStyleChanged);
2331 current_style.LinkHoverColorChanged += new EventHandler (TableStyleChanged);
2332 current_style.MappingNameChanged += new EventHandler (TableStyleChanged);
2333 current_style.PreferredColumnWidthChanged += new EventHandler (TableStyleChanged);
2334 current_style.PreferredRowHeightChanged += new EventHandler (TableStyleChanged);
2335 current_style.ReadOnlyChanged += new EventHandler (TableStyleChanged);
2336 current_style.RowHeadersVisibleChanged += new EventHandler (TableStyleChanged);
2337 current_style.RowHeaderWidthChanged += new EventHandler (TableStyleChanged);
2338 current_style.SelectionBackColorChanged += new EventHandler (TableStyleChanged);
2339 current_style.SelectionForeColorChanged += new EventHandler (TableStyleChanged);
2342 void TableStyleChanged (object sender, EventArgs args)
2345 CalcAreasAndInvalidate ();
2349 private void EnsureCellVisibility (DataGridCell cell)
2351 if (cell.ColumnNumber <= first_visible_column ||
2352 cell.ColumnNumber + 1 >= first_visible_column + visible_column_count) {
2354 first_visible_column = GetFirstColumnForColumnVisibility (first_visible_column, cell.ColumnNumber);
2355 int pixel = GetColumnStartingPixel (first_visible_column);
2356 ScrollToColumnInPixels (pixel);
2357 horiz_scrollbar.Value = pixel;
2361 if (cell.RowNumber < first_visible_row ||
2362 cell.RowNumber + 1 >= first_visible_row + visible_row_count) {
2364 if (cell.RowNumber + 1 >= first_visible_row + visible_row_count) {
2365 int old_first_visible_row = first_visible_row;
2366 first_visible_row = 1 + cell.RowNumber - visible_row_count;
2367 UpdateVisibleRowCount ();
2368 ScrollToRow (old_first_visible_row, first_visible_row);
2370 int old_first_visible_row = first_visible_row;
2371 first_visible_row = cell.RowNumber;
2372 UpdateVisibleRowCount ();
2373 ScrollToRow (old_first_visible_row, first_visible_row);
2376 vert_scrollbar.Value = first_visible_row;
2380 private void SetDataSource (object source, string member)
2382 SetDataSource (source, member, true);
2385 bool in_setdatasource;
2386 private void SetDataSource (object source, string member, bool recreate_rows)
2388 CurrencyManager old_lm = list_manager;
2390 /* we need this bool flag to work around a
2391 * problem with OnBindingContextChanged. once
2392 * that stuff works properly, remove this
2394 if (in_setdatasource)
2396 in_setdatasource = true;
2399 if (datasource == source && member == datamember)
2403 if (source != null && source as IListSource != null && source as IList != null)
2404 throw new Exception ("Wrong complex data binding source");
2406 datasource = source;
2407 datamember = member;
2412 current_cell = new DataGridCell ();
2414 if (list_manager != null)
2415 DisconnectListManagerEvents ();
2417 list_manager = null;
2419 /* create the new list manager */
2420 if (BindingContext != null && datasource != null)
2421 list_manager = (CurrencyManager) BindingContext [datasource, datamember];
2423 if (list_manager != null)
2424 ConnectListManagerEvents ();
2426 if (old_lm != list_manager) {
2429 /* reset first_visible_row to 0 here before
2430 * doing anything that'll requires us to
2431 * figure out if we need a scrollbar. */
2432 vert_scrollbar.Value = 0;
2433 horiz_scrollbar.Value = 0;
2434 first_visible_row = 0;
2437 RecreateDataGridRows (false);
2440 CalcAreasAndInvalidate ();
2442 in_setdatasource = false;
2444 OnDataSourceChanged (EventArgs.Empty);
2447 void RecreateDataGridRows (bool recalc)
2449 DataGridRelationshipRow[] new_rows = new DataGridRelationshipRow[RowsCount + (ShowEditRow ? 1 : 0)];
2450 int start_index = 0;
2452 start_index = rows.Length;
2453 Array.Copy (rows, 0, new_rows, 0, rows.Length < new_rows.Length ? rows.Length : new_rows.Length);
2456 for (int i = start_index; i < new_rows.Length; i ++) {
2457 new_rows[i] = new DataGridRelationshipRow (this);
2458 new_rows[i].height = RowHeight;
2460 new_rows[i].VerticalOffset = new_rows[i-1].VerticalOffset + new_rows[i-1].Height;
2463 // UIA Framework event: Updates collection list depending on binding
2464 CollectionChangeAction action = CollectionChangeAction.Refresh;
2466 if (new_rows.Length - rows.Length > 0)
2467 action = CollectionChangeAction.Add;
2469 action = CollectionChangeAction.Remove;
2474 CalcAreasAndInvalidate ();
2475 // UIA Framework event: Row added/removed
2476 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (action, -1));
2479 internal void UpdateRowsFrom (DataGridRelationshipRow row)
2481 int start_index = Array.IndexOf (rows, row);
2482 if (start_index == -1)
2485 for (int i = start_index + 1; i < rows.Length; i ++)
2486 rows[i].VerticalOffset = rows[i-1].VerticalOffset + rows[i-1].Height;
2488 CalcAreasAndInvalidate ();
2493 if (list_manager != null) {
2494 string list_name = list_manager.GetListName (null);
2495 if (TableStyles[list_name] == null) {
2496 // no style exists by the supplied name
2497 current_style.GridColumnStyles.Clear ();
2498 current_style.CreateColumnsForTable (false);
2499 } else if (CurrentTableStyle == grid_style ||
2500 CurrentTableStyle.MappingName != list_name) {
2501 // If the style has been defined by the user, use it
2502 // Also, if the user provided style is empty,
2503 // force a bind for it
2504 CurrentTableStyle = styles_collection[list_name];
2505 current_style.CreateColumnsForTable (current_style.GridColumnStyles.Count > 0);
2507 current_style.CreateColumnsForTable (true);
2510 current_style.CreateColumnsForTable (false);
2513 private void OnListManagerMetaDataChanged (object sender, EventArgs e)
2516 CalcAreasAndInvalidate ();
2519 private void OnListManagerPositionChanged (object sender, EventArgs e)
2521 // Set the field directly, as we are empty now and using CurrentRow
2522 // directly would add a new row in this case.
2523 if (list_manager.Count == 0) {
2524 current_cell = new DataGridCell (0, 0);
2528 from_positionchanged_handler = true;
2529 CurrentRow = list_manager.Position;
2530 from_positionchanged_handler = false;
2533 private void OnListManagerItemChanged (object sender, ItemChangedEventArgs e)
2535 // if it was us who created the new row in CurrentCell, ignore it and don't recreate the rows yet.
2539 if (e.Index == -1) {
2541 if (rows == null || RowsCount != rows.Length - (ShowEditRow ? 1 : 0))
2545 RecreateDataGridRows (true);
2548 InvalidateRow (e.Index);
2552 private void OnTableStylesCollectionChanged (object sender, CollectionChangeEventArgs e)
2554 if (ListManager == null)
2557 string list_name = ListManager.GetListName (null);
2559 case CollectionChangeAction.Add:
2560 if (e.Element != null && String.Compare (list_name, ((DataGridTableStyle)e.Element).MappingName, true) == 0) {
2561 CurrentTableStyle = (DataGridTableStyle)e.Element;
2562 // force to auto detect columns in case the new style is completely empty
2563 ((DataGridTableStyle) e.Element).CreateColumnsForTable (CurrentTableStyle.GridColumnStyles.Count > 0);
2566 case CollectionChangeAction.Remove:
2567 if (e.Element != null && String.Compare (list_name, ((DataGridTableStyle)e.Element).MappingName, true) == 0) {
2568 CurrentTableStyle = default_style;
2569 current_style.GridColumnStyles.Clear ();
2570 current_style.CreateColumnsForTable (false);
2573 case CollectionChangeAction.Refresh:
2574 if (CurrentTableStyle == default_style
2575 || String.Compare (list_name, CurrentTableStyle.MappingName, true) != 0) {
2576 DataGridTableStyle style = styles_collection [list_name];
2577 if (style != null) {
2578 CurrentTableStyle = style;
2579 current_style.CreateColumnsForTable (false);
2581 CurrentTableStyle = default_style;
2582 current_style.GridColumnStyles.Clear ();
2583 current_style.CreateColumnsForTable (false);
2588 CalcAreasAndInvalidate ();
2591 private void AddNewRow ()
2593 ListManager.EndCurrentEdit ();
2594 ListManager.AddNew ();
2597 private void Edit ()
2599 if (CurrentTableStyle.GridColumnStyles.Count == 0)
2602 if (!CurrentTableStyle.GridColumnStyles[CurrentColumn].bound)
2605 // if we don't have any rows nor the "new" cell, there's nothing to do
2606 if (ListManager != null && (ListManager.Count == 0 && !ListManager.AllowNew))
2610 is_changing = false;
2612 CurrentTableStyle.GridColumnStyles[CurrentColumn].Edit (ListManager,
2613 CurrentRow, GetCellBounds (CurrentRow, CurrentColumn),
2614 _readonly, null, true);
2617 private void EndEdit ()
2619 if (CurrentTableStyle.GridColumnStyles.Count == 0)
2622 if (!CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].bound)
2625 EndEdit (CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber],
2626 current_cell.RowNumber, false);
2629 private void ShiftSelection (int index)
2631 // we have to save off selection_start
2632 // because ResetSelection clobbers it
2633 int saved_selection_start = selection_start;
2637 selection_start = saved_selection_start;
2639 if (index >= selection_start) {
2640 start = selection_start;
2644 end = selection_start;
2647 if (start == -1) start = 0;
2649 for (int idx = start; idx <= end; idx ++)
2653 private void ScrollToColumnInPixels (int pixel)
2657 if (pixel > horiz_pixeloffset) // ScrollRight
2658 pixels = -1 * (pixel - horiz_pixeloffset);
2660 pixels = horiz_pixeloffset - pixel;
2662 Rectangle area = cells_area;
2664 if (ColumnHeadersVisible) {
2665 area.Y -= ColumnHeadersArea.Height;
2666 area.Height += ColumnHeadersArea.Height;
2669 horiz_pixeloffset = pixel;
2670 UpdateVisibleColumn ();
2674 XplatUI.ScrollWindow (Handle, area, pixels, 0, false);
2676 int pixel_offset = GetColumnStartingPixel (CurrentColumn);
2677 int next_pixel_offset = pixel_offset;
2679 if (CurrentColumn < CurrentTableStyle.GridColumnStyles.Count)
2681 next_pixel_offset += CurrentTableStyle.GridColumnStyles[CurrentColumn].Width;
2684 if (pixel_offset >= horiz_pixeloffset
2685 && next_pixel_offset < horiz_pixeloffset + cells_area.Width)
2689 private void ScrollToRow (int old_row, int new_row)
2694 if (new_row > old_row) { // Scrolldown
2695 for (i = old_row; i < new_row; i ++)
2696 pixels -= rows[i].Height;
2698 for (i = new_row; i < old_row; i ++)
2699 pixels += rows[i].Height;
2705 Rectangle rows_area = cells_area; // Cells area - partial rows space
2707 if (RowHeadersVisible) {
2708 rows_area.X -= RowHeaderWidth;
2709 rows_area.Width += RowHeaderWidth;
2712 /* scroll the window */
2713 XplatUI.ScrollWindow (Handle, rows_area, 0, pixels, false);
2715 /* if the row is still */
2716 if (CurrentRow >= first_visible_row && CurrentRow < first_visible_row + visible_row_count)
2721 private void ColumnResize (int column)
2723 CurrencyManager source = this.ListManager;
2724 DataGridColumnStyle style = CurrentTableStyle.GridColumnStyles[column];
2725 string headerText = style.HeaderText;
2726 using (Graphics g = base.CreateGraphics ()) {
2727 int rows = source.Count;
2728 int width = (int)g.MeasureString (headerText, CurrentTableStyle.HeaderFont).Width + 4;
2730 for (int i = 0; i < rows; i++) {
2731 int rowColWidth = (int)style.GetPreferredSize (g, style.GetColumnValueAtRow (source, i)).Width;
2732 if (rowColWidth > width)
2733 width = rowColWidth;
2735 if (style.Width != width)
2736 style.Width = width;
2740 private void RowResize (int row)
2742 CurrencyManager source = this.ListManager;
2743 using (Graphics g = base.CreateGraphics ()) {
2744 GridColumnStylesCollection columns = CurrentTableStyle.GridColumnStyles;
2745 int colCount = columns.Count;
2746 //int rowCount = source.Count;
2748 for (int i = 0; i < colCount; i++) {
2749 object val = columns[i].GetColumnValueAtRow (source, row);
2750 height = Math.Max (columns[i].GetPreferredHeight (g, val), height);
2752 if (this.DataGridRows[row].Height != height)
2753 this.DataGridRows[row].Height = height;
2756 #endregion Private Instance Methods
2759 static object AllowNavigationChangedEvent = new object ();
2760 static object BackButtonClickEvent = new object ();
2761 static object BackgroundColorChangedEvent = new object ();
2762 static object BorderStyleChangedEvent = new object ();
2763 static object CaptionVisibleChangedEvent = new object ();
2764 static object CurrentCellChangedEvent = new object ();
2765 static object DataSourceChangedEvent = new object ();
2766 static object FlatModeChangedEvent = new object ();
2767 static object NavigateEvent = new object ();
2768 static object ParentRowsLabelStyleChangedEvent = new object ();
2769 static object ParentRowsVisibleChangedEvent = new object ();
2770 static object ReadOnlyChangedEvent = new object ();
2771 static object RowHeaderClickEvent = new object ();
2772 static object ScrollEvent = new object ();
2773 static object ShowParentDetailsButtonClickEvent = new object ();
2775 public event EventHandler AllowNavigationChanged {
2776 add { Events.AddHandler (AllowNavigationChangedEvent, value); }
2777 remove { Events.RemoveHandler (AllowNavigationChangedEvent, value); }
2780 public event EventHandler BackButtonClick {
2781 add { Events.AddHandler (BackButtonClickEvent, value); }
2782 remove { Events.RemoveHandler (BackButtonClickEvent, value); }
2785 public event EventHandler BackgroundColorChanged {
2786 add { Events.AddHandler (BackgroundColorChangedEvent, value); }
2787 remove { Events.RemoveHandler (BackgroundColorChangedEvent, value); }
2791 [EditorBrowsable(EditorBrowsableState.Never)]
2792 public new event EventHandler BackgroundImageChanged {
2793 add { base.BackgroundImageChanged += value; }
2794 remove { base.BackgroundImageChanged -= value; }
2798 [EditorBrowsable(EditorBrowsableState.Never)]
2799 public new event EventHandler BackgroundImageLayoutChanged {
2800 add { base.BackgroundImageLayoutChanged += value; }
2801 remove { base.BackgroundImageLayoutChanged -= value; }
2805 [EditorBrowsable(EditorBrowsableState.Never)]
2806 public new event EventHandler TextChanged {
2807 add { base.TextChanged += value; }
2808 remove { base.TextChanged -= value; }
2812 [EditorBrowsable(EditorBrowsableState.Never)]
2813 public new event EventHandler CursorChanged {
2814 add { base.CursorChanged += value; }
2815 remove { base.CursorChanged -= value; }
2818 public event EventHandler BorderStyleChanged {
2819 add { Events.AddHandler (BorderStyleChangedEvent, value); }
2820 remove { Events.RemoveHandler (BorderStyleChangedEvent, value); }
2823 public event EventHandler CaptionVisibleChanged {
2824 add { Events.AddHandler (CaptionVisibleChangedEvent, value); }
2825 remove { Events.RemoveHandler (CaptionVisibleChangedEvent, value); }
2828 public event EventHandler CurrentCellChanged {
2829 add { Events.AddHandler (CurrentCellChangedEvent, value); }
2830 remove { Events.RemoveHandler (CurrentCellChangedEvent, value); }
2833 public event EventHandler DataSourceChanged {
2834 add { Events.AddHandler (DataSourceChangedEvent, value); }
2835 remove { Events.RemoveHandler (DataSourceChangedEvent, value); }
2838 public event EventHandler FlatModeChanged {
2839 add { Events.AddHandler (FlatModeChangedEvent, value); }
2840 remove { Events.RemoveHandler (FlatModeChangedEvent, value); }
2843 public event NavigateEventHandler Navigate {
2844 add { Events.AddHandler (NavigateEvent, value); }
2845 remove { Events.RemoveHandler (NavigateEvent, value); }
2848 public event EventHandler ParentRowsLabelStyleChanged {
2849 add { Events.AddHandler (ParentRowsLabelStyleChangedEvent, value); }
2850 remove { Events.RemoveHandler (ParentRowsLabelStyleChangedEvent, value); }
2853 public event EventHandler ParentRowsVisibleChanged {
2854 add { Events.AddHandler (ParentRowsVisibleChangedEvent, value); }
2855 remove { Events.RemoveHandler (ParentRowsVisibleChangedEvent, value); }
2858 public event EventHandler ReadOnlyChanged {
2859 add { Events.AddHandler (ReadOnlyChangedEvent, value); }
2860 remove { Events.RemoveHandler (ReadOnlyChangedEvent, value); }
2863 protected event EventHandler RowHeaderClick {
2864 add { Events.AddHandler (RowHeaderClickEvent, value); }
2865 remove { Events.RemoveHandler (RowHeaderClickEvent, value); }
2868 public event EventHandler Scroll {
2869 add { Events.AddHandler (ScrollEvent, value); }
2870 remove { Events.RemoveHandler (ScrollEvent, value); }
2873 public event EventHandler ShowParentDetailsButtonClick {
2874 add { Events.AddHandler (ShowParentDetailsButtonClickEvent, value); }
2875 remove { Events.RemoveHandler (ShowParentDetailsButtonClickEvent, value); }
2877 #endregion // Events
2879 #region Code originally in DataGridDrawingLogic.cs
2881 #region Local Variables
2884 Rectangle parent_rows;
2885 int width_of_all_columns;
2887 internal Rectangle caption_area;
2888 internal Rectangle column_headers_area; // Used columns header area
2889 internal int column_headers_max_width; // Total width (max width) for columns headrs
2890 internal Rectangle row_headers_area; // Used Headers rows area
2891 internal Rectangle cells_area;
2892 #endregion // Local Variables
2894 #region Public Instance Methods
2896 // Calc the max with of all columns
2897 private int CalcAllColumnsWidth ()
2900 int cnt = CurrentTableStyle.GridColumnStyles.Count;
2902 for (int col = 0; col < cnt; col++) {
2903 if (CurrentTableStyle.GridColumnStyles[col].bound == false) {
2906 width += CurrentTableStyle.GridColumnStyles[col].Width;
2911 // Gets a column from a pixel
2912 private int FromPixelToColumn (int pixel, out int column_x)
2915 int cnt = CurrentTableStyle.GridColumnStyles.Count;
2921 if (CurrentTableStyle.CurrentRowHeadersVisible) {
2922 width += row_headers_area.X + row_headers_area.Width;
2923 column_x += row_headers_area.X + row_headers_area.Width;
2928 for (int col = 0; col < cnt; col++) {
2929 if (CurrentTableStyle.GridColumnStyles[col].bound == false)
2932 width += CurrentTableStyle.GridColumnStyles[col].Width;
2937 column_x += CurrentTableStyle.GridColumnStyles[col].Width;
2943 internal int GetColumnStartingPixel (int my_col)
2946 int cnt = CurrentTableStyle.GridColumnStyles.Count;
2948 for (int col = 0; col < cnt; col++) {
2949 if (CurrentTableStyle.GridColumnStyles[col].bound == false) {
2956 width += CurrentTableStyle.GridColumnStyles[col].Width;
2962 // Which column has to be the first visible column to ensure a column visibility
2963 int GetFirstColumnForColumnVisibility (int current_first_visible_column, int column)
2965 int new_col = column;
2968 if (column > current_first_visible_column) { // Going forward
2969 for (new_col = column; new_col >= 0; new_col--) {
2970 if (!CurrentTableStyle.GridColumnStyles[new_col].bound)
2972 width += CurrentTableStyle.GridColumnStyles[new_col].Width;
2974 if (width >= cells_area.Width)
2976 //return new_col < CurrentTableStyle.GridColumnStyles.Count ? new_col + 1 : CurrentTableStyle.GridColumnStyles.Count;
2984 bool in_calc_grid_areas;
2985 void CalcGridAreas ()
2987 if (!IsHandleCreated) // Delay calculations until the handle is created
2990 /* make sure we don't happen to end up in this method again */
2991 if (in_calc_grid_areas)
2994 in_calc_grid_areas = true;
2996 /* Order is important. E.g. row headers max. height depends on caption */
2997 horiz_pixeloffset = 0;
3000 CalcParentButtons ();
3001 UpdateVisibleRowCount ();
3003 width_of_all_columns = CalcAllColumnsWidth ();
3004 CalcColumnHeaders ();
3007 bool needHoriz = false;
3008 bool needVert = false;
3010 /* figure out which scrollbars we need, and what the visible areas are */
3011 int visible_cells_width = cells_area.Width;
3012 int visible_cells_height = cells_area.Height;
3013 int allrows = RowsCount;
3015 if (ShowEditRow && RowsCount > 0)
3018 /* use a loop to iteratively calculate whether
3019 * we need horiz/vert scrollbars. */
3020 for (int i = 0; i < 3; i++) {
3022 visible_cells_width = cells_area.Width - vert_scrollbar.Width;
3024 visible_cells_height = cells_area.Height - horiz_scrollbar.Height;
3026 UpdateVisibleRowCount ();
3028 needHoriz = (width_of_all_columns > visible_cells_width);
3029 needVert = (allrows > MaxVisibleRowCount);
3032 int horiz_scrollbar_width = ClientRectangle.Width;
3033 int horiz_scrollbar_maximum = 0;
3034 int vert_scrollbar_height = 0;
3035 int vert_scrollbar_maximum = 0;
3038 SetUpVerticalScrollBar (out vert_scrollbar_height, out vert_scrollbar_maximum);
3041 SetUpHorizontalScrollBar (out horiz_scrollbar_maximum);
3043 cells_area.Width = visible_cells_width;
3044 cells_area.Height = visible_cells_height;
3046 if (needVert && needHoriz) {
3048 parent_rows.Width -= vert_scrollbar.Width;
3050 if (!ColumnHeadersVisible) {
3051 if (column_headers_area.X + column_headers_area.Width > vert_scrollbar.Location.X) {
3052 column_headers_area.Width -= vert_scrollbar.Width;
3056 horiz_scrollbar_width -= vert_scrollbar.Width;
3057 vert_scrollbar_height -= horiz_scrollbar.Height;
3061 if (row_headers_area.Y + row_headers_area.Height > ClientRectangle.Y + ClientRectangle.Height) {
3062 row_headers_area.Height -= horiz_scrollbar.Height;
3065 vert_scrollbar.Size = new Size (vert_scrollbar.Width,
3066 vert_scrollbar_height);
3068 vert_scrollbar.Maximum = vert_scrollbar_maximum;
3069 Controls.Add (vert_scrollbar);
3070 vert_scrollbar.Visible = true;
3072 Controls.Remove (vert_scrollbar);
3073 vert_scrollbar.Visible = false;
3077 horiz_scrollbar.Size = new Size (horiz_scrollbar_width,
3078 horiz_scrollbar.Height);
3080 horiz_scrollbar.Maximum = horiz_scrollbar_maximum;
3081 Controls.Add (horiz_scrollbar);
3082 horiz_scrollbar.Visible = true;
3084 Controls.Remove (horiz_scrollbar);
3085 horiz_scrollbar.Visible = false;
3088 UpdateVisibleColumn ();
3089 UpdateVisibleRowCount ();
3091 in_calc_grid_areas = false;
3096 caption_area.X = ClientRectangle.X;
3097 caption_area.Y = ClientRectangle.Y;
3098 caption_area.Width = ClientRectangle.Width;
3099 if (caption_visible) {
3100 caption_area.Height = CaptionFont.Height;
3101 if (caption_area.Height < back_button_image.Height)
3102 caption_area.Height = back_button_image.Height;
3103 caption_area.Height += 2;
3105 caption_area.Height = 0;
3108 void CalcCellsArea ()
3110 cells_area.X = ClientRectangle.X + row_headers_area.Width;
3111 cells_area.Y = column_headers_area.Y + column_headers_area.Height;
3112 cells_area.Width = ClientRectangle.X + ClientRectangle.Width - cells_area.X;
3113 if (cells_area.Width < 0)
3114 cells_area.Width = 0;
3115 cells_area.Height = ClientRectangle.Y + ClientRectangle.Height - cells_area.Y;
3116 if (cells_area.Height < 0)
3117 cells_area.Height = 0;
3120 void CalcColumnHeaders ()
3124 column_headers_area.X = ClientRectangle.X;
3125 column_headers_area.Y = parent_rows.Y + parent_rows.Height;
3127 // TODO: take into account Scrollbars
3128 column_headers_max_width = ClientRectangle.X + ClientRectangle.Width - column_headers_area.X;
3129 max_width_cols = column_headers_max_width;
3131 if (CurrentTableStyle.CurrentRowHeadersVisible)
3132 max_width_cols -= RowHeaderWidth;
3134 if (width_of_all_columns > max_width_cols) {
3135 column_headers_area.Width = column_headers_max_width;
3137 column_headers_area.Width = width_of_all_columns;
3139 if (CurrentTableStyle.CurrentRowHeadersVisible)
3140 column_headers_area.Width += RowHeaderWidth;
3143 if (ColumnHeadersVisible)
3144 column_headers_area.Height = CurrentTableStyle.HeaderFont.Height + 6;
3146 column_headers_area.Height = 0;
3149 void CalcParentRows ()
3151 parent_rows.X = ClientRectangle.X;
3152 parent_rows.Y = caption_area.Y + caption_area.Height;
3153 parent_rows.Width = ClientRectangle.Width;
3155 parent_rows.Height = (CaptionFont.Height + 3) * data_source_stack.Count;
3157 parent_rows.Height = 0;
3160 void CalcParentButtons ()
3162 if (data_source_stack.Count > 0 && CaptionVisible) {
3163 back_button_rect = new Rectangle (ClientRectangle.X + ClientRectangle.Width - 2 * (caption_area.Height - 2) - 8,
3164 caption_area.Height / 2 - back_button_image.Height / 2,
3165 back_button_image.Width, back_button_image.Height);
3166 parent_rows_button_rect = new Rectangle (ClientRectangle.X + ClientRectangle.Width - (caption_area.Height - 2) - 4,
3167 caption_area.Height / 2 - parent_rows_button_image.Height / 2,
3168 parent_rows_button_image.Width, parent_rows_button_image.Height);
3170 back_button_rect = parent_rows_button_rect = Rectangle.Empty;
3174 void CalcRowHeaders ()
3176 row_headers_area.X = ClientRectangle.X;
3177 row_headers_area.Y = column_headers_area.Y + column_headers_area.Height;
3178 row_headers_area.Height = ClientRectangle.Height + ClientRectangle.Y - row_headers_area.Y;
3180 if (CurrentTableStyle.CurrentRowHeadersVisible)
3181 row_headers_area.Width = RowHeaderWidth;
3183 row_headers_area.Width = 0;
3186 int GetVisibleRowCount (int visibleHeight)
3188 int rows_height = 0;
3190 for (r = FirstVisibleRow; r < rows.Length; r ++) {
3191 if (rows_height + rows[r].Height >= visibleHeight)
3193 rows_height += rows[r].Height;
3196 if (r <= rows.Length - 1)
3199 return r - FirstVisibleRow;
3202 void UpdateVisibleColumn ()
3204 visible_column_count = 0;
3206 if (CurrentTableStyle.GridColumnStyles.Count == 0)
3214 min_pixel = horiz_pixeloffset;
3215 if (CurrentTableStyle.CurrentRowHeadersVisible)
3216 min_pixel += row_headers_area.X + row_headers_area.Width;
3217 max_pixel = min_pixel + cells_area.Width;
3219 first_visible_column = FromPixelToColumn (min_pixel, out unused);
3220 max_col = FromPixelToColumn (max_pixel, out unused);
3222 for (int i = first_visible_column; i <= max_col; i ++) {
3223 if (CurrentTableStyle.GridColumnStyles[i].bound)
3224 visible_column_count++;
3227 if (first_visible_column + visible_column_count < CurrentTableStyle.GridColumnStyles.Count) {
3228 visible_column_count++; // Partially visible column
3232 void UpdateVisibleRowCount ()
3234 visible_row_count = GetVisibleRowCount (cells_area.Height);
3236 CalcRowHeaders (); // Height depends on num of visible rows
3239 void InvalidateCaption ()
3241 if (caption_area.IsEmpty)
3244 Invalidate (caption_area);
3247 void InvalidateRow (int row)
3249 if (row < FirstVisibleRow || row > FirstVisibleRow + VisibleRowCount)
3252 Rectangle rect_row = new Rectangle ();
3254 rect_row.X = cells_area.X;
3255 rect_row.Width = width_of_all_columns;
3256 if (rect_row.Width > cells_area.Width)
3257 rect_row.Width = cells_area.Width;
3258 rect_row.Height = rows[row].Height;
3259 rect_row.Y = cells_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
3260 Invalidate (rect_row);
3263 void InvalidateRowHeader (int row)
3265 Rectangle rect_rowhdr = new Rectangle ();
3266 rect_rowhdr.X = row_headers_area.X;
3267 rect_rowhdr.Width = row_headers_area.Width;
3268 rect_rowhdr.Height = rows[row].Height;
3269 rect_rowhdr.Y = row_headers_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
3270 Invalidate (rect_rowhdr);
3273 internal void InvalidateColumn (DataGridColumnStyle column)
3275 Rectangle rect_col = new Rectangle ();
3279 col = CurrentTableStyle.GridColumnStyles.IndexOf (column);
3284 rect_col.Width = column.Width;
3285 col_pixel = GetColumnStartingPixel (col);
3286 rect_col.X = cells_area.X + col_pixel - horiz_pixeloffset;
3287 rect_col.Y = cells_area.Y;
3288 rect_col.Height = cells_area.Height;
3289 Invalidate (rect_col);
3292 void DrawResizeLineVert (int x)
3294 XplatUI.DrawReversibleRectangle (Handle,
3295 new Rectangle (x, cells_area.Y, 1, cells_area.Height - 3),
3299 void DrawResizeLineHoriz (int y)
3301 XplatUI.DrawReversibleRectangle (Handle,
3302 new Rectangle (cells_area.X, y, cells_area.Width - 3, 1),
3306 void SetUpHorizontalScrollBar (out int maximum)
3308 maximum = width_of_all_columns;
3310 horiz_scrollbar.Location = new Point (ClientRectangle.X, ClientRectangle.Y +
3311 ClientRectangle.Height - horiz_scrollbar.Height);
3313 horiz_scrollbar.LargeChange = cells_area.Width;
3316 void SetUpVerticalScrollBar (out int height, out int maximum)
3320 y = ClientRectangle.Y + parent_rows.Y + parent_rows.Height;
3321 height = ClientRectangle.Height - parent_rows.Y - parent_rows.Height;
3323 vert_scrollbar.Location = new Point (ClientRectangle.X +
3324 ClientRectangle.Width - vert_scrollbar.Width, y);
3326 maximum = RowsCount;
3328 if (ShowEditRow && RowsCount > 0) {
3332 vert_scrollbar.LargeChange = VLargeChange;
3335 #endregion // Public Instance Methods
3337 #region Instance Properties
3338 // Returns the ColumnHeaders area excluding the rectangle shared with RowHeaders
3339 internal Rectangle ColumnHeadersArea {
3341 Rectangle columns_area = column_headers_area;
3343 if (CurrentTableStyle.CurrentRowHeadersVisible) {
3344 columns_area.X += RowHeaderWidth;
3345 columns_area.Width -= RowHeaderWidth;
3347 return columns_area;
3351 internal Rectangle RowHeadersArea {
3352 get { return row_headers_area; }
3355 internal Rectangle ParentRowsArea {
3356 get { return parent_rows; }
3361 return MaxVisibleRowCount;
3365 #endregion Instance Properties
3367 #endregion // Code originally in DataGridDrawingLogic.cs
3369 #region UIA Framework: Methods, Properties and Events
3371 static object UIACollectionChangedEvent = new object ();
3372 static object UIASelectionChangedEvent = new object ();
3373 static object UIAColumnHeadersVisibleChangedEvent = new object ();
3374 static object UIAGridCellChangedEvent = new object ();
3376 internal ScrollBar UIAHScrollBar {
3377 get { return horiz_scrollbar; }
3380 internal ScrollBar UIAVScrollBar {
3381 get { return vert_scrollbar; }
3384 internal DataGridTableStyle UIACurrentTableStyle {
3385 get { return current_style; }
3388 internal int UIASelectedRows {
3389 get { return selected_rows.Count; }
3392 internal Rectangle UIAColumnHeadersArea {
3393 get { return ColumnHeadersArea; }
3396 internal Rectangle UIACaptionArea {
3397 get { return caption_area; }
3400 internal Rectangle UIACellsArea {
3401 get { return cells_area; }
3404 internal int UIARowHeight {
3405 get { return RowHeight; }
3408 internal event CollectionChangeEventHandler UIACollectionChanged {
3409 add { Events.AddHandler (UIACollectionChangedEvent, value); }
3410 remove { Events.RemoveHandler (UIACollectionChangedEvent, value); }
3413 internal event CollectionChangeEventHandler UIASelectionChanged {
3414 add { Events.AddHandler (UIASelectionChangedEvent, value); }
3415 remove { Events.RemoveHandler (UIASelectionChangedEvent, value); }
3418 internal event EventHandler UIAColumnHeadersVisibleChanged {
3419 add { Events.AddHandler (UIAColumnHeadersVisibleChangedEvent, value); }
3420 remove { Events.RemoveHandler (UIAColumnHeadersVisibleChangedEvent, value); }
3423 internal event CollectionChangeEventHandler UIAGridCellChanged {
3424 add { Events.AddHandler (UIAGridCellChangedEvent, value); }
3425 remove { Events.RemoveHandler (UIAGridCellChangedEvent, value); }
3428 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
3430 CollectionChangeEventHandler eh
3431 = (CollectionChangeEventHandler) Events [UIACollectionChangedEvent];
3436 internal void OnUIASelectionChangedEvent (CollectionChangeEventArgs args)
3438 CollectionChangeEventHandler eh
3439 = (CollectionChangeEventHandler) Events [UIASelectionChangedEvent];
3444 internal void OnUIAColumnHeadersVisibleChanged ()
3446 EventHandler eh = (EventHandler) Events [UIAColumnHeadersVisibleChangedEvent];
3448 eh (this, EventArgs.Empty);
3451 internal void OnUIAGridCellChanged (CollectionChangeEventArgs args)
3453 CollectionChangeEventHandler eh
3454 = (CollectionChangeEventHandler) Events [UIAGridCellChangedEvent];
3459 #endregion // UIA Framework: Methods, Properties and Events