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")]
115 [ComplexBindingProperties ("DataSource", "DataMember")]
116 [ClassInterface (ClassInterfaceType.AutoDispatch)]
119 public class DataGrid : Control, ISupportInitialize, IDataGridEditingService
125 public enum HitTestType
137 public sealed class HitTestInfo
139 public static readonly HitTestInfo Nowhere = null;
143 DataGrid.HitTestType type;
145 #region Private Constructors
146 internal HitTestInfo () : this (-1, -1, HitTestType.None)
150 internal HitTestInfo (int row, int column, DataGrid.HitTestType type)
153 this.column = column;
159 #region Public Instance Properties
161 get { return column; }
167 public DataGrid.HitTestType Type {
170 #endregion //Public Instance Properties
172 public override bool Equals (object value)
174 if (!(value is HitTestInfo))
177 HitTestInfo obj = (HitTestInfo) value;
178 return (obj.Column == column && obj.Row == row && obj.Type ==type);
181 public override int GetHashCode ()
186 public override string ToString ()
188 return "{ " + type + "," + row + "," + column + "}";
192 #region Local Variables
193 /* cached theme defaults */
194 static readonly Color def_background_color = ThemeEngine.Current.DataGridBackgroundColor;
195 static readonly Color def_caption_backcolor = ThemeEngine.Current.DataGridCaptionBackColor;
196 static readonly Color def_caption_forecolor = ThemeEngine.Current.DataGridCaptionForeColor;
197 static readonly Color def_parent_rows_backcolor = ThemeEngine.Current.DataGridParentRowsBackColor;
198 static readonly Color def_parent_rows_forecolor = ThemeEngine.Current.DataGridParentRowsForeColor;
201 // XXX this needs addressing. Control.background_color should not be internal.
202 new Color background_color;
203 Color caption_backcolor;
204 Color caption_forecolor;
205 Color parent_rows_backcolor;
206 Color parent_rows_forecolor;
208 /* flags to determine which areas of the datagrid are shown */
209 bool caption_visible;
210 bool parent_rows_visible;
212 GridTableStylesCollection styles_collection;
213 DataGridParentRowsLabelStyle parent_rows_label_style;
214 DataGridTableStyle default_style;
215 DataGridTableStyle grid_style;
216 DataGridTableStyle current_style;
219 DataGridCell current_cell;
220 Hashtable selected_rows;
221 int selection_start; // used for range selection
223 /* layout/rendering */
224 bool allow_navigation;
225 int first_visible_row;
226 int first_visible_column;
227 int visible_row_count;
228 int visible_column_count;
232 HScrollBar horiz_scrollbar;
233 VScrollBar vert_scrollbar;
234 int horiz_pixeloffset;
236 internal Bitmap back_button_image;
237 internal Rectangle back_button_rect;
238 internal bool back_button_mouseover;
239 internal bool back_button_active;
240 internal Bitmap parent_rows_button_image;
241 internal Rectangle parent_rows_button_rect;
242 internal bool parent_rows_button_mouseover;
243 internal bool parent_rows_button_active;
248 CurrencyManager list_manager;
249 bool refetch_list_manager = true;
251 DataGridRelationshipRow[] rows;
253 /* column resize fields */
254 bool column_resize_active;
256 int resize_column_width_delta;
259 /* row resize fields */
260 bool row_resize_active;
262 int resize_row_height_delta;
265 /* used to make sure we don't endlessly recurse calling set_CurrentCell and OnListManagerPositionChanged */
266 bool from_positionchanged_handler;
269 bool cursor_in_add_row;
270 bool add_row_changed;
271 internal bool is_editing; // Current cell is edit mode
273 bool commit_row_changes = true; // Whether to commit current edit or cancel it
274 bool adding_new_row; // Used to temporary ignore the new row added by CurrencyManager.AddNew in CurrentCell
276 internal Stack data_source_stack;
278 #endregion // Local Variables
280 #region Public Constructors
283 allow_navigation = true;
284 background_color = def_background_color;
285 border_style = BorderStyle.Fixed3D;
286 caption_backcolor = def_caption_backcolor;
287 caption_forecolor = def_caption_forecolor;
288 caption_text = string.Empty;
289 caption_visible = true;
290 datamember = string.Empty;
291 parent_rows_backcolor = def_parent_rows_backcolor;
292 parent_rows_forecolor = def_parent_rows_forecolor;
293 parent_rows_visible = true;
294 current_cell = new DataGridCell ();
295 parent_rows_label_style = DataGridParentRowsLabelStyle.Both;
296 selected_rows = new Hashtable ();
297 selection_start = -1;
298 rows = new DataGridRelationshipRow [0];
300 default_style = new DataGridTableStyle (true);
301 grid_style = new DataGridTableStyle ();
303 styles_collection = new GridTableStylesCollection (this);
304 styles_collection.CollectionChanged += new CollectionChangeEventHandler (OnTableStylesCollectionChanged);
306 CurrentTableStyle = grid_style;
308 horiz_scrollbar = new ImplicitHScrollBar ();
309 horiz_scrollbar.Scroll += new ScrollEventHandler (GridHScrolled);
310 vert_scrollbar = new ImplicitVScrollBar ();
311 vert_scrollbar.Scroll += new ScrollEventHandler (GridVScrolled);
313 SetStyle (ControlStyles.UserMouse, true);
315 data_source_stack = new Stack ();
317 back_button_image = ResourceImageLoader.Get ("go-previous.png");
318 back_button_image.MakeTransparent (Color.Transparent);
319 parent_rows_button_image = ResourceImageLoader.Get ("go-top.png");
320 parent_rows_button_image.MakeTransparent (Color.Transparent);
323 #endregion // Public Constructor
325 #region Public Instance Properties
328 public bool AllowNavigation {
329 get { return allow_navigation; }
331 if (allow_navigation != value) {
332 allow_navigation = value;
333 OnAllowNavigationChanged (EventArgs.Empty);
339 public bool AllowSorting {
340 get { return grid_style.AllowSorting; }
341 set { grid_style.AllowSorting = value; }
344 public Color AlternatingBackColor {
345 get { return grid_style.AlternatingBackColor; }
346 set { grid_style.AlternatingBackColor = value; }
349 public override Color BackColor {
350 get { return grid_style.BackColor; }
351 set { grid_style.BackColor = value; }
354 public Color BackgroundColor {
355 get { return background_color; }
357 if (background_color != value) {
358 background_color = value;
359 OnBackgroundColorChanged (EventArgs.Empty);
366 [EditorBrowsable(EditorBrowsableState.Never)]
367 public override Image BackgroundImage {
368 get { return base.BackgroundImage; }
370 if (base.BackgroundImage == value)
373 base.BackgroundImage = value;
380 [EditorBrowsable (EditorBrowsableState.Never)]
381 public override ImageLayout BackgroundImageLayout {
382 get { return base.BackgroundImageLayout; }
383 set { base.BackgroundImageLayout = value; }
388 [DefaultValue(BorderStyle.Fixed3D)]
389 public BorderStyle BorderStyle {
390 get { return InternalBorderStyle; }
392 InternalBorderStyle = value;
393 CalcAreasAndInvalidate ();
394 OnBorderStyleChanged (EventArgs.Empty);
398 public Color CaptionBackColor {
399 get { return caption_backcolor; }
401 if (caption_backcolor != value) {
402 caption_backcolor = value;
403 InvalidateCaption ();
410 public Font CaptionFont {
412 if (caption_font == null)
413 return new Font (Font, FontStyle.Bold);
418 if (caption_font != null && caption_font.Equals (value))
421 caption_font = value;
422 CalcAreasAndInvalidate ();
426 public Color CaptionForeColor {
427 get { return caption_forecolor; }
429 if (caption_forecolor != value) {
430 caption_forecolor = value;
431 InvalidateCaption ();
438 public string CaptionText {
439 get { return caption_text; }
441 if (caption_text != value) {
442 caption_text = value;
443 InvalidateCaption ();
449 public bool CaptionVisible {
450 get { return caption_visible; }
452 if (caption_visible != value) {
454 caption_visible = value;
455 CalcAreasAndInvalidate ();
456 OnCaptionVisibleChanged (EventArgs.Empty);
462 public bool ColumnHeadersVisible {
463 get { return grid_style.ColumnHeadersVisible; }
465 if (grid_style.ColumnHeadersVisible != value) {
466 grid_style.ColumnHeadersVisible = value;
469 // UIA Framework: To keep track of header
470 OnUIAColumnHeadersVisibleChanged ();
476 bool setting_current_cell;
479 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
480 public DataGridCell CurrentCell {
481 get { return current_cell; }
483 if (setting_current_cell)
485 setting_current_cell = true;
487 if (!IsHandleCreated) {
488 setting_current_cell = false;
489 throw new Exception ("CurrentCell cannot be set at this time.");
492 /* Even if we are on the same cell, we could need to actually start edition */
493 if (current_cell.Equals (value) && is_editing) {
494 setting_current_cell = false;
498 /* make sure the new cell fits in the correct bounds for [row,column] */
499 if (ReadOnly && value.RowNumber > RowsCount - 1)
500 value.RowNumber = RowsCount - 1;
501 else if (value.RowNumber > RowsCount)
502 value.RowNumber = RowsCount;
503 if (value.ColumnNumber >= CurrentTableStyle.GridColumnStyles.Count)
504 value.ColumnNumber = CurrentTableStyle.GridColumnStyles.Count == 0 ? 0 : CurrentTableStyle.GridColumnStyles.Count - 1;
507 /* now make sure we don't go negative */
508 if (value.RowNumber < 0) value.RowNumber = 0;
509 if (value.ColumnNumber < 0) value.ColumnNumber = 0;
511 bool was_changing = is_changing;
513 add_row_changed = add_row_changed || was_changing;
516 if (value.RowNumber != current_cell.RowNumber) {
517 if (!from_positionchanged_handler) {
519 if (commit_row_changes)
520 ListManager.EndCurrentEdit ();
522 ListManager.CancelCurrentEdit ();
524 catch (Exception e) {
525 DialogResult r = MessageBox.Show (String.Format ("{0} Do you wish to correct the value?", e.Message),
526 "Error when committing the row to the original data source",
527 MessageBoxButtons.YesNo);
528 if (r == DialogResult.Yes) {
529 InvalidateRowHeader (value.RowNumber);
530 InvalidateRowHeader (current_cell.RowNumber);
531 setting_current_cell = false;
536 ListManager.CancelCurrentEdit ();
540 if (value.RowNumber == RowsCount && !ListManager.AllowNew)
544 int old_row = current_cell.RowNumber;
546 current_cell = value;
548 EnsureCellVisibility (value);
550 // by default, edition in existing rows is commited, and for new ones is discarded, unless
551 // we receive actual input data from the user
552 if (CurrentRow == RowsCount && ListManager.AllowNew) {
553 commit_row_changes = false;
554 cursor_in_add_row = true;
555 add_row_changed = false;
557 adding_new_row = true;
559 adding_new_row = false;
562 cursor_in_add_row = false;
563 commit_row_changes = true;
566 InvalidateRowHeader (old_row);
567 InvalidateRowHeader (current_cell.RowNumber);
569 list_manager.Position = current_cell.RowNumber;
571 OnCurrentCellChanged (EventArgs.Empty);
573 if (!from_positionchanged_handler)
576 setting_current_cell = false;
580 internal void EditRowChanged (DataGridColumnStyle column_style)
582 if (cursor_in_add_row) {
583 if (!commit_row_changes) { // first change in add row, time to show another row in the ui
584 commit_row_changes = true;
585 RecreateDataGridRows (true);
591 get { return current_cell.RowNumber; }
592 set { CurrentCell = new DataGridCell (value, current_cell.ColumnNumber); }
596 get { return current_cell.ColumnNumber; }
597 set { CurrentCell = new DataGridCell (current_cell.RowNumber, value); }
601 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
602 public int CurrentRowIndex {
604 if (ListManager == null)
609 set { CurrentRow = value; }
613 [EditorBrowsable(EditorBrowsableState.Never)]
614 public override Cursor Cursor {
615 get { return base.Cursor; }
616 set { base.Cursor = value; }
620 [Editor ("System.Windows.Forms.Design.DataMemberListEditor, " + Consts.AssemblySystem_Design, "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
621 public string DataMember {
622 get { return datamember; }
624 if (BindingContext != null) {
625 SetDataSource (datasource, value);
628 if (list_manager != null)
631 refetch_list_manager = true;
637 [RefreshProperties(RefreshProperties.Repaint)]
639 [AttributeProvider (typeof (IListSource))]
641 [TypeConverter("System.Windows.Forms.Design.DataSourceConverter, " + Consts.AssemblySystem_Design)]
643 public object DataSource {
644 get { return datasource; }
646 if (BindingContext != null) {
647 SetDataSource (value, ListManager == null ? datamember : string.Empty);
651 if (list_manager != null)
652 datamember = string.Empty;
654 if (list_manager != null)
656 refetch_list_manager = true;
661 protected override Size DefaultSize {
662 get { return new Size (130, 80); }
666 public int FirstVisibleColumn {
667 get { return first_visible_column; }
670 [DefaultValue(false)]
671 public bool FlatMode {
672 get { return flatmode; }
674 if (flatmode != value) {
676 OnFlatModeChanged (EventArgs.Empty);
682 public override Color ForeColor {
683 get { return grid_style.ForeColor; }
684 set { grid_style.ForeColor = value; }
687 public Color GridLineColor {
688 get { return grid_style.GridLineColor; }
690 if (value == Color.Empty)
691 throw new ArgumentException ("Color.Empty value is invalid.");
693 grid_style.GridLineColor = value;
697 [DefaultValue(DataGridLineStyle.Solid)]
698 public DataGridLineStyle GridLineStyle {
699 get { return grid_style.GridLineStyle; }
700 set { grid_style.GridLineStyle = value; }
703 public Color HeaderBackColor {
704 get { return grid_style.HeaderBackColor; }
706 if (value == Color.Empty)
707 throw new ArgumentException ("Color.Empty value is invalid.");
709 grid_style.HeaderBackColor = value;
713 public Font HeaderFont {
714 get { return grid_style.HeaderFont; }
715 set { grid_style.HeaderFont = value; }
718 public Color HeaderForeColor {
719 get { return grid_style.HeaderForeColor; }
720 set { grid_style.HeaderForeColor = value; }
723 protected ScrollBar HorizScrollBar {
724 get { return horiz_scrollbar; }
726 internal ScrollBar HScrollBar {
727 get { return horiz_scrollbar; }
730 internal int HorizPixelOffset {
731 get { return horiz_pixeloffset; }
734 internal bool IsChanging {
735 get { return is_changing; }
738 public object this [DataGridCell cell] {
739 get { return this [cell.RowNumber, cell.ColumnNumber]; }
740 set { this [cell.RowNumber, cell.ColumnNumber] = value; }
743 public object this [int rowIndex, int columnIndex] {
744 get { return CurrentTableStyle.GridColumnStyles[columnIndex].GetColumnValueAtRow (ListManager,
747 CurrentTableStyle.GridColumnStyles[columnIndex].SetColumnValueAtRow (ListManager,
751 // UIA Framework: Raising changes in datasource.
752 OnUIAGridCellChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh,
753 new DataGridCell (rowIndex,
759 public Color LinkColor {
760 get { return grid_style.LinkColor; }
761 set { grid_style.LinkColor = value; }
764 internal Font LinkFont {
765 get { return new Font (Font, FontStyle.Underline); }
772 [EditorBrowsable(EditorBrowsableState.Never)]
773 public Color LinkHoverColor {
774 get { return grid_style.LinkHoverColor; }
775 set { grid_style.LinkHoverColor = value; }
779 [EditorBrowsable(EditorBrowsableState.Advanced)]
780 protected internal CurrencyManager ListManager {
782 if (list_manager == null && refetch_list_manager) {
783 SetDataSource (datasource, datamember);
784 refetch_list_manager = false;
789 set { throw new NotSupportedException ("Operation is not supported."); }
792 public Color ParentRowsBackColor {
793 get { return parent_rows_backcolor; }
795 if (parent_rows_backcolor != value) {
796 parent_rows_backcolor = value;
797 if (parent_rows_visible) {
804 public Color ParentRowsForeColor {
805 get { return parent_rows_forecolor; }
807 if (parent_rows_forecolor != value) {
808 parent_rows_forecolor = value;
809 if (parent_rows_visible) {
816 [DefaultValue(DataGridParentRowsLabelStyle.Both)]
817 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
818 public DataGridParentRowsLabelStyle ParentRowsLabelStyle {
819 get { return parent_rows_label_style; }
821 if (parent_rows_label_style != value) {
822 parent_rows_label_style = value;
823 if (parent_rows_visible) {
827 OnParentRowsLabelStyleChanged (EventArgs.Empty);
833 public bool ParentRowsVisible {
834 get { return parent_rows_visible; }
836 if (parent_rows_visible != value) {
837 parent_rows_visible = value;
838 CalcAreasAndInvalidate ();
839 OnParentRowsVisibleChanged (EventArgs.Empty);
844 // Settting this property seems to have no effect.
846 [TypeConverter(typeof(DataGridPreferredColumnWidthTypeConverter))]
847 public int PreferredColumnWidth {
848 get { return grid_style.PreferredColumnWidth; }
849 set { grid_style.PreferredColumnWidth = value; }
852 public int PreferredRowHeight {
853 get { return grid_style.PreferredRowHeight; }
854 set { grid_style.PreferredRowHeight = value; }
857 [DefaultValue(false)]
858 public bool ReadOnly {
859 get { return _readonly; }
861 if (_readonly != value) {
863 OnReadOnlyChanged (EventArgs.Empty);
864 CalcAreasAndInvalidate ();
870 public bool RowHeadersVisible {
871 get { return grid_style.RowHeadersVisible; }
872 set { grid_style.RowHeadersVisible = value; }
876 public int RowHeaderWidth {
877 get { return grid_style.RowHeaderWidth; }
878 set { grid_style.RowHeaderWidth = value; }
881 internal DataGridRelationshipRow[] DataGridRows {
886 public Color SelectionBackColor {
887 get { return grid_style.SelectionBackColor; }
888 set { grid_style.SelectionBackColor = value; }
891 public Color SelectionForeColor {
892 get { return grid_style.SelectionForeColor; }
893 set { grid_style.SelectionForeColor = value; }
896 public override ISite Site {
897 get { return base.Site; }
898 set { base.Site = value; }
902 [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
903 public GridTableStylesCollection TableStyles {
904 get { return styles_collection; }
909 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
910 [EditorBrowsable(EditorBrowsableState.Never)]
911 public override string Text {
912 get { return base.Text; }
913 set { base.Text = value; }
917 [EditorBrowsable(EditorBrowsableState.Advanced)]
918 protected ScrollBar VertScrollBar {
919 get { return vert_scrollbar; }
921 internal ScrollBar VScrollBar {
922 get { return vert_scrollbar; }
926 public int VisibleColumnCount {
927 get { return visible_column_count; }
931 public int VisibleRowCount {
932 get { return visible_row_count; }
935 #endregion // Public Instance Properties
937 #region Private Instance Properties
938 internal DataGridTableStyle CurrentTableStyle {
939 get { return current_style; }
941 if (current_style != value) {
942 if (current_style != null)
943 DisconnectTableStyleEvents ();
945 current_style = value;
947 if (current_style != null) {
948 current_style.DataGrid = this;
949 ConnectTableStyleEvents ();
951 CalcAreasAndInvalidate ();
956 internal int FirstVisibleRow {
957 get { return first_visible_row; }
960 // As opposed to VisibleRowCount, this value is the maximum
961 // *possible* number of visible rows given our area.
962 internal int MaxVisibleRowCount {
964 return cells_area.Height / RowHeight;
968 internal int RowsCount {
969 get { return ListManager != null ? ListManager.Count : 0; }
972 internal int RowHeight {
974 if (CurrentTableStyle.CurrentPreferredRowHeight > Font.Height + 3 + 1 /* line */)
975 return CurrentTableStyle.CurrentPreferredRowHeight;
977 return Font.Height + 3 + 1 /* line */;
981 internal override bool ScaleChildrenInternal {
982 get { return false; }
985 internal bool ShowEditRow {
987 if (ListManager != null && !ListManager.AllowNew)
994 internal bool ShowParentRows {
995 get { return ParentRowsVisible && data_source_stack.Count > 0; }
998 #endregion Private Instance Properties
1000 #region Public Instance Methods
1002 void AbortEditing ()
1005 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].Abort (current_cell.RowNumber);
1006 is_changing = false;
1007 InvalidateRowHeader (current_cell.RowNumber);
1011 public bool BeginEdit (DataGridColumnStyle gridColumn, int rowNumber)
1016 int column = CurrentTableStyle.GridColumnStyles.IndexOf (gridColumn);
1020 CurrentCell = new DataGridCell (rowNumber, column);
1022 /* force editing of CurrentCell if we aren't already editing */
1028 public void BeginInit ()
1032 protected virtual void CancelEditing ()
1034 if (CurrentTableStyle.GridColumnStyles.Count == 0)
1037 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].ConcedeFocus ();
1040 if (current_cell.ColumnNumber < CurrentTableStyle.GridColumnStyles.Count)
1041 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].Abort (current_cell.RowNumber);
1042 InvalidateRowHeader (current_cell.RowNumber);
1045 if (cursor_in_add_row && !is_changing) {
1046 ListManager.CancelCurrentEdit ();
1049 is_changing = false;
1053 public void Collapse (int row)
1055 if (!rows[row].IsExpanded)
1059 rows[row].IsExpanded = false;
1060 for (int i = 1; i < rows.Length - row; i ++)
1061 rows[row + i].VerticalOffset -= rows[row].RelationHeight;
1063 rows[row].height -= rows[row].RelationHeight;
1064 rows[row].RelationHeight = 0;
1065 ResumeLayout (false);
1067 /* XX need to redraw from @row down */
1068 CalcAreasAndInvalidate ();
1071 protected internal virtual void ColumnStartedEditing (Control editingControl)
1073 ColumnStartedEditing (editingControl.Bounds);
1076 protected internal virtual void ColumnStartedEditing (Rectangle bounds)
1078 bool need_invalidate = is_changing == false;
1079 // XXX calculate the row header to invalidate
1080 // instead of using CurrentRow
1083 if (cursor_in_add_row && need_invalidate)
1084 RecreateDataGridRows (true);
1086 if (need_invalidate)
1087 InvalidateRowHeader (CurrentRow);
1090 protected override AccessibleObject CreateAccessibilityInstance ()
1092 return base.CreateAccessibilityInstance ();
1095 protected virtual DataGridColumnStyle CreateGridColumn (PropertyDescriptor prop)
1097 return CreateGridColumn (prop, false);
1100 [MonoTODO ("Not implemented, will throw NotImplementedException")]
1101 protected virtual DataGridColumnStyle CreateGridColumn (PropertyDescriptor prop, bool isDefault)
1103 throw new NotImplementedException();
1106 protected override void Dispose (bool disposing)
1108 base.Dispose (disposing);
1111 public bool EndEdit (DataGridColumnStyle gridColumn, int rowNumber, bool shouldAbort)
1113 if (shouldAbort || (_readonly || gridColumn.TableStyleReadOnly || gridColumn.ReadOnly))
1114 gridColumn.Abort (rowNumber);
1116 gridColumn.Commit (ListManager, rowNumber);
1117 gridColumn.ConcedeFocus ();
1120 if (is_editing || is_changing) {
1122 is_changing = false;
1123 InvalidateRowHeader (rowNumber);
1128 public void EndInit ()
1130 if (grid_style != null)
1131 grid_style.DataGrid = this;
1134 public void Expand (int row)
1136 if (rows[row].IsExpanded)
1139 rows[row].IsExpanded = true;
1143 string[] relations = CurrentTableStyle.Relations;
1144 StringBuilder relation_builder = new StringBuilder ("");
1146 for (i = 0; i < relations.Length; i ++) {
1148 relation_builder.Append ("\n");
1150 relation_builder.Append (relations[i]);
1152 string relation_text = relation_builder.ToString ();
1154 SizeF measured_area = TextRenderer.MeasureString (relation_text, LinkFont);
1156 rows[row].relation_area = new Rectangle (cells_area.X + 1,
1157 0, /* updated as needed at the usage sites for relation_area */
1158 (int)measured_area.Width + 4,
1159 Font.Height * relations.Length);
1161 for (i = 1; i < rows.Length - row; i ++)
1162 rows[row + i].VerticalOffset += rows[row].relation_area.Height;
1163 rows[row].height += rows[row].relation_area.Height;
1164 rows[row].RelationHeight = rows[row].relation_area.Height;
1166 /* XX need to redraw from @row down */
1167 CalcAreasAndInvalidate ();
1170 public Rectangle GetCellBounds (DataGridCell dgc)
1172 return GetCellBounds (dgc.RowNumber, dgc.ColumnNumber);
1175 public Rectangle GetCellBounds (int row, int col)
1177 Rectangle bounds = new Rectangle ();
1180 bounds.Width = CurrentTableStyle.GridColumnStyles[col].Width;
1181 bounds.Height = rows[row].Height - rows[row].RelationHeight;
1182 bounds.Y = cells_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
1183 col_pixel = GetColumnStartingPixel (col);
1184 bounds.X = cells_area.X + col_pixel - horiz_pixeloffset;
1188 public Rectangle GetCurrentCellBounds ()
1190 return GetCellBounds (current_cell.RowNumber, current_cell.ColumnNumber);
1193 protected virtual string GetOutputTextDelimiter ()
1195 return string.Empty;
1198 protected virtual void GridHScrolled (object sender, ScrollEventArgs se)
1200 if (se.NewValue == horiz_pixeloffset ||
1201 se.Type == ScrollEventType.EndScroll) {
1205 ScrollToColumnInPixels (se.NewValue);
1208 protected virtual void GridVScrolled (object sender, ScrollEventArgs se)
1210 int old_first_visible_row = first_visible_row;
1211 first_visible_row = se.NewValue;
1213 if (first_visible_row == old_first_visible_row)
1216 UpdateVisibleRowCount ();
1218 if (first_visible_row == old_first_visible_row)
1221 ScrollToRow (old_first_visible_row, first_visible_row);
1224 public HitTestInfo HitTest (Point position)
1226 return HitTest (position.X, position.Y);
1229 const int RESIZE_HANDLE_HORIZ_SIZE = 5;
1230 const int RESIZE_HANDLE_VERT_SIZE = 3;
1232 // From Point to Cell
1233 public HitTestInfo HitTest (int x, int y)
1235 if (column_headers_area.Contains (x, y)) {
1236 int offset_x = x + horiz_pixeloffset;
1238 int column_under_mouse = FromPixelToColumn (offset_x, out column_x);
1240 if (column_under_mouse == -1)
1241 return new HitTestInfo (-1, -1, HitTestType.None);
1243 if ((column_x + CurrentTableStyle.GridColumnStyles[column_under_mouse].Width - offset_x < RESIZE_HANDLE_HORIZ_SIZE)
1244 && column_under_mouse < CurrentTableStyle.GridColumnStyles.Count) {
1246 return new HitTestInfo (-1, column_under_mouse, HitTestType.ColumnResize);
1249 return new HitTestInfo (-1, column_under_mouse, HitTestType.ColumnHeader);
1253 if (row_headers_area.Contains (x, y)) {
1255 int rcnt = FirstVisibleRow + VisibleRowCount;
1256 for (int r = FirstVisibleRow; r < rcnt; r++) {
1257 posy = cells_area.Y + rows[r].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
1258 if (y <= posy + rows[r].Height) {
1259 if ((posy + rows[r].Height) - y < RESIZE_HANDLE_VERT_SIZE) {
1260 return new HitTestInfo (r, -1, HitTestType.RowResize);
1263 return new HitTestInfo (r, -1, HitTestType.RowHeader);
1269 if (caption_area.Contains (x, y)) {
1270 return new HitTestInfo (-1, -1, HitTestType.Caption);
1273 if (parent_rows.Contains (x, y)) {
1274 return new HitTestInfo (-1, -1, HitTestType.ParentRows);
1277 int pos_y, pos_x, width;
1278 int rowcnt = FirstVisibleRow + VisibleRowCount;
1279 for (int row = FirstVisibleRow; row < rowcnt; row++) {
1281 pos_y = cells_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
1282 if (y <= pos_y + rows[row].Height) {
1284 int column_cnt = first_visible_column + visible_column_count;
1285 if (column_cnt > 0) {
1286 for (int column = first_visible_column; column < column_cnt; column++) {
1287 if (CurrentTableStyle.GridColumnStyles[column].bound == false)
1289 col_pixel = GetColumnStartingPixel (column);
1290 pos_x = cells_area.X + col_pixel - horiz_pixeloffset;
1291 width = CurrentTableStyle.GridColumnStyles[column].Width;
1293 if (x <= pos_x + width) { // Column found
1294 return new HitTestInfo (row, column, HitTestType.Cell);
1298 else if (CurrentTableStyle.HasRelations) {
1299 /* XXX this needs checking against MS somehow... */
1300 if (x < rows[row].relation_area.X + rows[row].relation_area.Width)
1301 return new HitTestInfo (row, 0/*XXX?*/, HitTestType.Cell);
1308 return new HitTestInfo ();
1311 public bool IsExpanded (int rowNumber)
1313 return (rows[rowNumber].IsExpanded);
1316 public bool IsSelected (int row)
1318 return rows[row].IsSelected;
1321 public void NavigateBack ()
1323 if (data_source_stack.Count == 0)
1326 DataGridDataSource source = (DataGridDataSource)data_source_stack.Pop ();
1327 list_manager = source.list_manager;
1329 selected_rows = source.SelectedRows;
1330 selection_start = source.SelectionStart;
1331 SetDataSource (source.data_source, source.data_member);
1333 CurrentCell = source.current;
1336 public void NavigateTo (int rowNumber, string relationName)
1338 if (allow_navigation == false)
1341 DataGridDataSource previous_source = new DataGridDataSource (this, list_manager, datasource, datamember, list_manager.Current, CurrentCell);
1342 previous_source.Rows = rows;
1343 previous_source.SelectedRows = selected_rows;
1344 previous_source.SelectionStart = selection_start;
1346 data_source_stack.Push (previous_source);
1349 selected_rows = new Hashtable ();
1350 selection_start = -1;
1352 DataMember = String.Format ("{0}.{1}", DataMember, relationName);
1353 OnDataSourceChanged (EventArgs.Empty);
1356 protected virtual void OnAllowNavigationChanged (EventArgs e)
1358 EventHandler eh = (EventHandler)(Events [AllowNavigationChangedEvent]);
1363 protected void OnBackButtonClicked (object sender, EventArgs e)
1365 EventHandler eh = (EventHandler)(Events [BackButtonClickEvent]);
1370 protected override void OnBackColorChanged (EventArgs e)
1372 base.OnBackColorChanged (e);
1375 protected virtual void OnBackgroundColorChanged (EventArgs e)
1377 EventHandler eh = (EventHandler)(Events [BackgroundColorChangedEvent]);
1382 protected override void OnBindingContextChanged (EventArgs e)
1384 base.OnBindingContextChanged (e);
1386 SetDataSource (datasource, datamember);
1389 protected virtual void OnBorderStyleChanged (EventArgs e)
1391 EventHandler eh = (EventHandler)(Events [BorderStyleChangedEvent]);
1396 protected virtual void OnCaptionVisibleChanged (EventArgs e)
1398 EventHandler eh = (EventHandler)(Events [CaptionVisibleChangedEvent]);
1403 protected virtual void OnCurrentCellChanged (EventArgs e)
1405 EventHandler eh = (EventHandler)(Events [CurrentCellChangedEvent]);
1410 protected virtual void OnDataSourceChanged (EventArgs e)
1412 EventHandler eh = (EventHandler)(Events [DataSourceChangedEvent]);
1417 protected override void OnEnter (EventArgs e)
1423 protected virtual void OnFlatModeChanged (EventArgs e)
1425 EventHandler eh = (EventHandler)(Events [FlatModeChangedEvent]);
1430 protected override void OnFontChanged (EventArgs e)
1433 base.OnFontChanged (e);
1436 protected override void OnForeColorChanged (EventArgs e)
1438 base.OnForeColorChanged (e);
1441 protected override void OnHandleCreated (EventArgs e)
1443 base.OnHandleCreated (e);
1444 SetDataSource (datasource, datamember);
1447 protected override void OnHandleDestroyed (EventArgs e)
1449 base.OnHandleDestroyed (e);
1452 // It seems we have repeated code with ProcessKeyPreview, specifically
1453 // the call to ProcessGridKey. In practice it seems this event is *never* fired
1454 // since the key events are handled by the current column's textbox.
1455 // We are keeping commented anyway, in case we need to actually call it.
1456 protected override void OnKeyDown (KeyEventArgs ke)
1458 base.OnKeyDown (ke);
1460 /*if (ProcessGridKey (ke) == true)
1463 // TODO: we probably don't need this check,
1464 // since current_cell wouldn't have been set
1465 // to something invalid
1466 if (CurrentTableStyle.GridColumnStyles.Count > 0) {
1467 CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].OnKeyDown
1468 (ke, current_cell.RowNumber, current_cell.ColumnNumber);
1472 protected override void OnKeyPress (KeyPressEventArgs kpe)
1474 base.OnKeyPress (kpe);
1477 protected override void OnLayout (LayoutEventArgs levent)
1479 base.OnLayout (levent);
1480 CalcAreasAndInvalidate ();
1483 protected override void OnLeave (EventArgs e)
1488 if (commit_row_changes)
1489 ListManager.EndCurrentEdit ();
1491 ListManager.CancelCurrentEdit ();
1494 protected override void OnMouseDown (MouseEventArgs e)
1496 base.OnMouseDown (e);
1498 bool ctrl_pressed = ((Control.ModifierKeys & Keys.Control) != 0);
1499 bool shift_pressed = ((Control.ModifierKeys & Keys.Shift) != 0);
1501 HitTestInfo testinfo;
1502 testinfo = HitTest (e.X, e.Y);
1504 switch (testinfo.Type) {
1505 case HitTestType.Cell:
1506 if (testinfo.Row < 0 || testinfo.Column < 0)
1509 if (rows[testinfo.Row].IsExpanded) {
1510 Rectangle relation_area = rows[testinfo.Row].relation_area;
1511 relation_area.Y = rows[testinfo.Row].VerticalOffset + cells_area.Y + rows[testinfo.Row].Height - rows[testinfo.Row].RelationHeight;
1512 if (relation_area.Contains (e.X, e.Y)) {
1513 /* the click happened in the relation area, navigate to the new table */
1514 int relative = e.Y - relation_area.Y;
1515 NavigateTo (testinfo.Row, CurrentTableStyle.Relations[relative / LinkFont.Height]);
1520 DataGridCell new_cell = new DataGridCell (testinfo.Row, testinfo.Column);
1522 if ((new_cell.Equals (current_cell) == false) || (!is_editing)) {
1524 CurrentCell = new_cell;
1527 CurrentTableStyle.GridColumnStyles[testinfo.Column].OnMouseDown (e, testinfo.Row, testinfo.Column);
1532 case HitTestType.RowHeader:
1533 bool expansion_click = false;
1534 if (CurrentTableStyle.HasRelations) {
1535 if (e.X > row_headers_area.X + row_headers_area.Width / 2) {
1536 /* it's in the +/- space */
1537 if (IsExpanded (testinfo.Row))
1538 Collapse (testinfo.Row);
1540 Expand (testinfo.Row);
1542 expansion_click = true;
1547 CurrentRow = testinfo.Row;
1549 if (!ctrl_pressed && !shift_pressed && !expansion_click) {
1550 ResetSelection (); // Invalidates selected rows
1553 if ((shift_pressed || expansion_click) && selection_start != -1) {
1554 ShiftSelection (testinfo.Row);
1555 } else { // ctrl_pressed or single item
1556 selection_start = testinfo.Row;
1557 Select (testinfo.Row);
1560 OnRowHeaderClick (EventArgs.Empty);
1564 case HitTestType.ColumnHeader:
1565 if (CurrentTableStyle.GridColumnStyles.Count == 0)
1568 if (AllowSorting == false)
1571 if (ListManager.List is IBindingList == false)
1574 // Don't do any sort if we are empty, as .net does
1575 if (ListManager.Count == 0)
1578 ListSortDirection direction = ListSortDirection.Ascending;
1579 PropertyDescriptor prop = CurrentTableStyle.GridColumnStyles[testinfo.Column].PropertyDescriptor;
1580 IBindingList list = (IBindingList) ListManager.List;
1582 if (list.SortProperty != null) {
1583 CurrentTableStyle.GridColumnStyles[list.SortProperty].ArrowDrawingMode
1584 = DataGridColumnStyle.ArrowDrawing.No;
1587 if (prop == list.SortProperty && list.SortDirection == ListSortDirection.Ascending) {
1588 direction = ListSortDirection.Descending;
1591 CurrentTableStyle.GridColumnStyles[testinfo.Column].ArrowDrawingMode =
1592 direction == ListSortDirection.Ascending ?
1593 DataGridColumnStyle.ArrowDrawing.Ascending : DataGridColumnStyle.ArrowDrawing.Descending;
1595 list.ApplySort (prop, direction);
1597 if (this.is_editing)
1598 //CurrentTableStyle.GridColumnStyles[CurrentColumn].UpdateUI ();
1599 this.InvalidateColumn (CurrentTableStyle.GridColumnStyles[CurrentColumn]);
1603 case HitTestType.ColumnResize:
1604 if (e.Clicks == 2) {
1606 ColumnResize (testinfo.Column);
1608 resize_column = testinfo.Column;
1609 column_resize_active = true;
1610 resize_column_x = e.X;
1611 resize_column_width_delta = 0;
1613 DrawResizeLineVert (resize_column_x);
1617 case HitTestType.RowResize:
1618 if (e.Clicks == 2) {
1620 RowResize (testinfo.Row);
1622 resize_row = testinfo.Row;
1623 row_resize_active = true;
1625 resize_row_height_delta = 0;
1627 DrawResizeLineHoriz (resize_row_y);
1631 case HitTestType.Caption:
1632 if (back_button_rect.Contains (e.X, e.Y)) {
1633 back_button_active = true;
1634 Invalidate (back_button_rect);
1636 if (parent_rows_button_rect.Contains (e.X, e.Y)) {
1637 parent_rows_button_active = true;
1638 Invalidate (parent_rows_button_rect);
1647 protected override void OnMouseLeave (EventArgs e)
1649 base.OnMouseLeave (e);
1652 protected override void OnMouseMove (MouseEventArgs e)
1654 base.OnMouseMove (e);
1656 if (column_resize_active) {
1657 /* erase the old line */
1658 DrawResizeLineVert (resize_column_x + resize_column_width_delta);
1660 resize_column_width_delta = e.X - resize_column_x;
1662 /* draw the new line */
1663 DrawResizeLineVert (resize_column_x + resize_column_width_delta);
1666 else if (row_resize_active) {
1667 /* erase the old line */
1668 DrawResizeLineHoriz (resize_row_y + resize_row_height_delta);
1670 resize_row_height_delta = e.Y - resize_row_y;
1672 /* draw the new line */
1673 DrawResizeLineHoriz (resize_row_y + resize_row_height_delta);
1677 /* determine the cursor to use */
1678 HitTestInfo testinfo;
1679 testinfo = HitTest (e.X, e.Y);
1681 switch (testinfo.Type) {
1682 case HitTestType.ColumnResize:
1683 Cursor = Cursors.VSplit;
1685 case HitTestType.RowResize:
1686 Cursor = Cursors.HSplit;
1688 case HitTestType.Caption:
1689 Cursor = Cursors.Default;
1690 if (back_button_rect.Contains (e.X, e.Y)) {
1691 if (!back_button_mouseover)
1692 Invalidate (back_button_rect);
1693 back_button_mouseover = true;
1694 } else if (back_button_mouseover) {
1695 Invalidate (back_button_rect);
1696 back_button_mouseover = false;
1699 if (parent_rows_button_rect.Contains (e.X, e.Y)) {
1700 if (parent_rows_button_mouseover)
1701 Invalidate (parent_rows_button_rect);
1702 parent_rows_button_mouseover = true;
1703 } else if (parent_rows_button_mouseover) {
1704 Invalidate (parent_rows_button_rect);
1705 parent_rows_button_mouseover = false;
1708 case HitTestType.Cell:
1709 if (rows[testinfo.Row].IsExpanded) {
1710 Rectangle relation_area = rows[testinfo.Row].relation_area;
1711 relation_area.Y = rows[testinfo.Row].VerticalOffset + cells_area.Y + rows[testinfo.Row].Height - rows[testinfo.Row].RelationHeight;
1712 if (relation_area.Contains (e.X, e.Y)) {
1713 Cursor = Cursors.Hand;
1718 Cursor = Cursors.Default;
1720 case HitTestType.RowHeader:
1721 if (e.Button == MouseButtons.Left)
1722 ShiftSelection (testinfo.Row);
1724 Cursor = Cursors.Default;
1727 Cursor = Cursors.Default;
1733 protected override void OnMouseUp (MouseEventArgs e)
1737 if (column_resize_active) {
1738 column_resize_active = false;
1739 if (resize_column_width_delta + CurrentTableStyle.GridColumnStyles[resize_column].Width < 0)
1740 resize_column_width_delta = -CurrentTableStyle.GridColumnStyles[resize_column].Width;
1741 CurrentTableStyle.GridColumnStyles[resize_column].Width += resize_column_width_delta;
1742 width_of_all_columns += resize_column_width_delta;
1745 } else if (row_resize_active) {
1746 row_resize_active = false;
1748 if (resize_row_height_delta + rows[resize_row].Height < 0)
1749 resize_row_height_delta = -rows[resize_row].Height;
1751 rows[resize_row].height = rows[resize_row].Height + resize_row_height_delta;
1752 for (int i = resize_row + 1; i < rows.Length; i ++)
1753 rows[i].VerticalOffset += resize_row_height_delta;
1756 CalcAreasAndInvalidate ();
1757 } else if (back_button_active) {
1758 if (back_button_rect.Contains (e.X, e.Y)) {
1759 Invalidate (back_button_rect);
1761 OnBackButtonClicked (this, EventArgs.Empty);
1763 back_button_active = false;
1764 } else if (parent_rows_button_active) {
1765 if (parent_rows_button_rect.Contains (e.X, e.Y)) {
1766 Invalidate (parent_rows_button_rect);
1767 ParentRowsVisible = !ParentRowsVisible;
1768 OnShowParentDetailsButtonClicked (this, EventArgs.Empty);
1770 parent_rows_button_active = false;
1774 protected override void OnMouseWheel (MouseEventArgs e)
1776 base.OnMouseWheel (e);
1778 bool ctrl_pressed = ((Control.ModifierKeys & Keys.Control) != 0);
1781 if (ctrl_pressed) { // scroll horizontally
1782 if (!horiz_scrollbar.Visible)
1787 pixels = Math.Max (horiz_scrollbar.Minimum,
1788 horiz_scrollbar.Value - horiz_scrollbar.LargeChange);
1791 pixels = Math.Min (horiz_scrollbar.Maximum - horiz_scrollbar.LargeChange + 1,
1792 horiz_scrollbar.Value + horiz_scrollbar.LargeChange);
1795 GridHScrolled (this, new ScrollEventArgs (ScrollEventType.ThumbPosition, pixels));
1796 horiz_scrollbar.Value = pixels;
1798 if (!vert_scrollbar.Visible)
1803 pixels = Math.Max (vert_scrollbar.Minimum,
1804 vert_scrollbar.Value - vert_scrollbar.LargeChange);
1807 pixels = Math.Min (vert_scrollbar.Maximum - vert_scrollbar.LargeChange + 1,
1808 vert_scrollbar.Value + vert_scrollbar.LargeChange);
1811 GridVScrolled (this, new ScrollEventArgs (ScrollEventType.ThumbPosition, pixels));
1812 vert_scrollbar.Value = pixels;
1816 protected void OnNavigate (NavigateEventArgs e)
1818 EventHandler eh = (EventHandler)(Events [NavigateEvent]);
1823 protected override void OnPaint (PaintEventArgs pe)
1825 ThemeEngine.Current.DataGridPaint (pe, this);
1828 protected override void OnPaintBackground (PaintEventArgs ebe)
1832 protected virtual void OnParentRowsLabelStyleChanged (EventArgs e)
1834 EventHandler eh = (EventHandler)(Events [ParentRowsLabelStyleChangedEvent]);
1839 protected virtual void OnParentRowsVisibleChanged (EventArgs e)
1841 EventHandler eh = (EventHandler)(Events [ParentRowsVisibleChangedEvent]);
1846 protected virtual void OnReadOnlyChanged (EventArgs e)
1848 EventHandler eh = (EventHandler)(Events [ReadOnlyChangedEvent]);
1853 protected override void OnResize (EventArgs e)
1858 protected void OnRowHeaderClick (EventArgs e)
1860 EventHandler eh = (EventHandler)(Events [RowHeaderClickEvent]);
1865 protected void OnScroll (EventArgs e)
1867 EventHandler eh = (EventHandler)(Events [ScrollEvent]);
1872 protected void OnShowParentDetailsButtonClicked (object sender, EventArgs e)
1874 EventHandler eh = (EventHandler)(Events [ShowParentDetailsButtonClickEvent]);
1879 protected override bool ProcessDialogKey (Keys keyData)
1881 return ProcessGridKey (new KeyEventArgs (keyData));
1884 void UpdateSelectionAfterCursorMove (bool extend_selection)
1886 if (extend_selection) {
1888 ShiftSelection (CurrentRow);
1891 selection_start = CurrentRow;
1895 protected bool ProcessGridKey (KeyEventArgs ke)
1897 bool ctrl_pressed = ((ke.Modifiers & Keys.Control) != 0);
1898 //bool alt_pressed = ((ke.Modifiers & Keys.Alt) != 0);
1899 bool shift_pressed = ((ke.Modifiers & Keys.Shift) != 0);
1901 switch (ke.KeyCode) {
1908 if (cursor_in_add_row && CurrentRow > 0)
1918 CurrentTableStyle.GridColumnStyles[CurrentColumn].EnterNullValue ();
1929 if (shift_pressed) {
1930 if (CurrentColumn > 0)
1932 else if ((CurrentRow > 0) && (CurrentColumn == 0))
1933 CurrentCell = new DataGridCell (CurrentRow - 1, CurrentTableStyle.GridColumnStyles.Count - 1);
1935 if (CurrentColumn < CurrentTableStyle.GridColumnStyles.Count - 1)
1937 else if ((CurrentRow <= RowsCount) && (CurrentColumn == CurrentTableStyle.GridColumnStyles.Count - 1))
1938 CurrentCell = new DataGridCell (CurrentRow + 1, 0);
1941 UpdateSelectionAfterCursorMove (false);
1947 CurrentColumn = CurrentTableStyle.GridColumnStyles.Count - 1;
1949 if (CurrentColumn < CurrentTableStyle.GridColumnStyles.Count - 1) {
1951 } else if (CurrentRow < RowsCount - 1
1952 || (CurrentRow == RowsCount - 1
1953 && !cursor_in_add_row)) {
1954 CurrentCell = new DataGridCell (CurrentRow + 1, 0);
1958 UpdateSelectionAfterCursorMove (false);
1966 if (current_cell.ColumnNumber > 0)
1968 else if (CurrentRow > 0)
1969 CurrentCell = new DataGridCell (CurrentRow - 1, CurrentTableStyle.GridColumnStyles.Count - 1);
1972 UpdateSelectionAfterCursorMove (false);
1979 else if (CurrentRow > 0)
1982 UpdateSelectionAfterCursorMove (shift_pressed);
1988 CurrentRow = RowsCount - 1;
1989 else if (CurrentRow < RowsCount - 1)
1991 else if (CurrentRow == RowsCount - 1 && cursor_in_add_row && (add_row_changed || is_changing))
1993 else if (CurrentRow == RowsCount - 1 && !cursor_in_add_row && !shift_pressed)
1996 UpdateSelectionAfterCursorMove (shift_pressed);
2001 if (CurrentRow > VLargeChange)
2002 CurrentRow -= VLargeChange;
2006 UpdateSelectionAfterCursorMove (shift_pressed);
2011 if (CurrentRow < RowsCount - VLargeChange)
2012 CurrentRow += VLargeChange;
2014 CurrentRow = RowsCount - 1;
2016 UpdateSelectionAfterCursorMove (shift_pressed);
2022 CurrentCell = new DataGridCell (0, 0);
2026 UpdateSelectionAfterCursorMove (ctrl_pressed && shift_pressed);
2032 CurrentCell = new DataGridCell (RowsCount - 1, CurrentTableStyle.GridColumnStyles.Count - 1);
2034 CurrentColumn = CurrentTableStyle.GridColumnStyles.Count - 1;
2036 UpdateSelectionAfterCursorMove (ctrl_pressed && shift_pressed);
2043 else if (selected_rows.Keys.Count > 0) {
2044 // the removal of the items in the source will cause to
2045 // reset the selection, so we need a copy of it.
2046 int [] rows = new int [selected_rows.Keys.Count];
2047 selected_rows.Keys.CopyTo (rows, 0);
2049 // reverse order to keep index sanity
2050 int edit_row_index = ShowEditRow ? RowsCount : -1; // new cell is +1
2051 for (int i = rows.Length - 1; i >= 0; i--)
2052 if (rows [i] != edit_row_index)
2053 ListManager.RemoveAt (rows [i]);
2055 CalcAreasAndInvalidate ();
2061 return false; // message not processed
2064 protected override bool ProcessKeyPreview (ref Message m)
2066 if ((Msg) m.Msg == Msg.WM_KEYDOWN) {
2067 Keys key = (Keys) m.WParam.ToInt32 ();
2068 KeyEventArgs ke = new KeyEventArgs (key);
2069 if (ProcessGridKey (ke))
2072 // if we receive a key event, make sure that input is actually
2073 // taken into account.
2076 InvalidateRow (current_cell.RowNumber);
2081 return base.ProcessKeyPreview (ref m);
2084 protected bool ProcessTabKey (Keys keyData)
2089 public void ResetAlternatingBackColor ()
2091 grid_style.AlternatingBackColor = default_style.AlternatingBackColor;
2094 public override void ResetBackColor ()
2096 grid_style.BackColor = default_style.BackColor;
2099 public override void ResetForeColor ()
2101 grid_style.ForeColor = default_style.ForeColor;
2104 public void ResetGridLineColor ()
2106 grid_style.GridLineColor = default_style.GridLineColor;
2109 public void ResetHeaderBackColor ()
2111 grid_style.HeaderBackColor = default_style.HeaderBackColor;
2114 public void ResetHeaderFont ()
2116 grid_style.HeaderFont = null;
2119 public void ResetHeaderForeColor ()
2121 grid_style.HeaderForeColor = default_style.HeaderForeColor;
2124 public void ResetLinkColor ()
2126 grid_style.LinkColor = default_style.LinkColor;
2129 public void ResetLinkHoverColor ()
2131 grid_style.LinkHoverColor = default_style.LinkHoverColor;
2134 protected void ResetSelection ()
2136 InvalidateSelection ();
2137 selected_rows.Clear ();
2138 selection_start = -1;
2141 void InvalidateSelection ()
2143 foreach (int row in selected_rows.Keys) {
2144 rows[row].IsSelected = false;
2145 InvalidateRow (row);
2149 public void ResetSelectionBackColor ()
2151 grid_style.SelectionBackColor = default_style.SelectionBackColor;
2154 public void ResetSelectionForeColor ()
2156 grid_style.SelectionForeColor = default_style.SelectionForeColor;
2159 public void Select (int row)
2163 if (selected_rows.Count == 0)
2164 selection_start = row;
2167 // UIA Framework: To raise event only when selecting
2168 bool wasSelected = rows [row].IsSelected;
2171 selected_rows[row] = true;
2172 rows[row].IsSelected = true;
2174 InvalidateRow (row);
2179 OnUIASelectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, row));
2184 public void SetDataBinding (object dataSource, string dataMember)
2186 SetDataSource (dataSource, dataMember);
2189 protected virtual bool ShouldSerializeAlternatingBackColor ()
2191 return (grid_style.AlternatingBackColor != default_style.AlternatingBackColor);
2194 protected virtual bool ShouldSerializeBackgroundColor ()
2196 return (background_color != def_background_color);
2199 protected virtual bool ShouldSerializeCaptionBackColor ()
2201 return (caption_backcolor != def_caption_backcolor);
2204 protected virtual bool ShouldSerializeCaptionForeColor ()
2206 return caption_forecolor != def_caption_forecolor;
2209 protected virtual bool ShouldSerializeGridLineColor ()
2211 return grid_style.GridLineColor != default_style.GridLineColor;
2214 protected virtual bool ShouldSerializeHeaderBackColor ()
2216 return grid_style.HeaderBackColor != default_style.HeaderBackColor;
2219 protected bool ShouldSerializeHeaderFont ()
2221 return grid_style.HeaderFont != default_style.HeaderFont;
2224 protected virtual bool ShouldSerializeHeaderForeColor ()
2226 return grid_style.HeaderForeColor != default_style.HeaderForeColor;
2229 protected virtual bool ShouldSerializeLinkHoverColor ()
2231 return grid_style.LinkHoverColor != grid_style.LinkHoverColor;
2234 protected virtual bool ShouldSerializeParentRowsBackColor ()
2236 return parent_rows_backcolor != def_parent_rows_backcolor;
2239 protected virtual bool ShouldSerializeParentRowsForeColor ()
2241 return parent_rows_backcolor != def_parent_rows_backcolor;
2244 protected bool ShouldSerializePreferredRowHeight ()
2246 return grid_style.PreferredRowHeight != default_style.PreferredRowHeight;
2249 protected bool ShouldSerializeSelectionBackColor ()
2251 return grid_style.SelectionBackColor != default_style.SelectionBackColor;
2254 protected virtual bool ShouldSerializeSelectionForeColor ()
2256 return grid_style.SelectionForeColor != default_style.SelectionForeColor;
2259 public void SubObjectsSiteChange (bool site)
2263 public void UnSelect (int row)
2266 // UIA Framework: To raise event only when unselecting
2267 bool wasSelected = rows [row].IsSelected;
2270 rows[row].IsSelected = false;
2271 selected_rows.Remove (row);
2272 InvalidateRow (row);
2275 // UIA Framework: Raises selection event
2277 OnUIASelectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, row));
2280 #endregion // Public Instance Methods
2282 #region Private Instance Methods
2284 internal void CalcAreasAndInvalidate ()
2290 private void ConnectListManagerEvents ()
2292 list_manager.MetaDataChanged += new EventHandler (OnListManagerMetaDataChanged);
2293 list_manager.PositionChanged += new EventHandler (OnListManagerPositionChanged);
2294 list_manager.ItemChanged += new ItemChangedEventHandler (OnListManagerItemChanged);
2297 private void DisconnectListManagerEvents ()
2299 list_manager.MetaDataChanged -= new EventHandler (OnListManagerMetaDataChanged);
2300 list_manager.PositionChanged -= new EventHandler (OnListManagerPositionChanged);
2301 list_manager.ItemChanged -= new ItemChangedEventHandler (OnListManagerItemChanged);
2304 void DisconnectTableStyleEvents ()
2306 current_style.AllowSortingChanged -= new EventHandler (TableStyleChanged);
2307 current_style.AlternatingBackColorChanged -= new EventHandler (TableStyleChanged);
2308 current_style.BackColorChanged -= new EventHandler (TableStyleChanged);
2309 current_style.ColumnHeadersVisibleChanged -= new EventHandler (TableStyleChanged);
2310 current_style.ForeColorChanged -= new EventHandler (TableStyleChanged);
2311 current_style.GridLineColorChanged -= new EventHandler (TableStyleChanged);
2312 current_style.GridLineStyleChanged -= new EventHandler (TableStyleChanged);
2313 current_style.HeaderBackColorChanged -= new EventHandler (TableStyleChanged);
2314 current_style.HeaderFontChanged -= new EventHandler (TableStyleChanged);
2315 current_style.HeaderForeColorChanged -= new EventHandler (TableStyleChanged);
2316 current_style.LinkColorChanged -= new EventHandler (TableStyleChanged);
2317 current_style.LinkHoverColorChanged -= new EventHandler (TableStyleChanged);
2318 current_style.MappingNameChanged -= new EventHandler (TableStyleChanged);
2319 current_style.PreferredColumnWidthChanged -= new EventHandler (TableStyleChanged);
2320 current_style.PreferredRowHeightChanged -= new EventHandler (TableStyleChanged);
2321 current_style.ReadOnlyChanged -= new EventHandler (TableStyleChanged);
2322 current_style.RowHeadersVisibleChanged -= new EventHandler (TableStyleChanged);
2323 current_style.RowHeaderWidthChanged -= new EventHandler (TableStyleChanged);
2324 current_style.SelectionBackColorChanged -= new EventHandler (TableStyleChanged);
2325 current_style.SelectionForeColorChanged -= new EventHandler (TableStyleChanged);
2328 void ConnectTableStyleEvents ()
2330 current_style.AllowSortingChanged += new EventHandler (TableStyleChanged);
2331 current_style.AlternatingBackColorChanged += new EventHandler (TableStyleChanged);
2332 current_style.BackColorChanged += new EventHandler (TableStyleChanged);
2333 current_style.ColumnHeadersVisibleChanged += new EventHandler (TableStyleChanged);
2334 current_style.ForeColorChanged += new EventHandler (TableStyleChanged);
2335 current_style.GridLineColorChanged += new EventHandler (TableStyleChanged);
2336 current_style.GridLineStyleChanged += new EventHandler (TableStyleChanged);
2337 current_style.HeaderBackColorChanged += new EventHandler (TableStyleChanged);
2338 current_style.HeaderFontChanged += new EventHandler (TableStyleChanged);
2339 current_style.HeaderForeColorChanged += new EventHandler (TableStyleChanged);
2340 current_style.LinkColorChanged += new EventHandler (TableStyleChanged);
2341 current_style.LinkHoverColorChanged += new EventHandler (TableStyleChanged);
2342 current_style.MappingNameChanged += new EventHandler (TableStyleChanged);
2343 current_style.PreferredColumnWidthChanged += new EventHandler (TableStyleChanged);
2344 current_style.PreferredRowHeightChanged += new EventHandler (TableStyleChanged);
2345 current_style.ReadOnlyChanged += new EventHandler (TableStyleChanged);
2346 current_style.RowHeadersVisibleChanged += new EventHandler (TableStyleChanged);
2347 current_style.RowHeaderWidthChanged += new EventHandler (TableStyleChanged);
2348 current_style.SelectionBackColorChanged += new EventHandler (TableStyleChanged);
2349 current_style.SelectionForeColorChanged += new EventHandler (TableStyleChanged);
2352 void TableStyleChanged (object sender, EventArgs args)
2355 CalcAreasAndInvalidate ();
2359 private void EnsureCellVisibility (DataGridCell cell)
2361 if (cell.ColumnNumber <= first_visible_column ||
2362 cell.ColumnNumber + 1 >= first_visible_column + visible_column_count) {
2364 first_visible_column = GetFirstColumnForColumnVisibility (first_visible_column, cell.ColumnNumber);
2365 int pixel = GetColumnStartingPixel (first_visible_column);
2366 ScrollToColumnInPixels (pixel);
2367 horiz_scrollbar.Value = pixel;
2371 if (cell.RowNumber < first_visible_row ||
2372 cell.RowNumber + 1 >= first_visible_row + visible_row_count) {
2374 if (cell.RowNumber + 1 >= first_visible_row + visible_row_count) {
2375 int old_first_visible_row = first_visible_row;
2376 first_visible_row = 1 + cell.RowNumber - visible_row_count;
2377 UpdateVisibleRowCount ();
2378 ScrollToRow (old_first_visible_row, first_visible_row);
2380 int old_first_visible_row = first_visible_row;
2381 first_visible_row = cell.RowNumber;
2382 UpdateVisibleRowCount ();
2383 ScrollToRow (old_first_visible_row, first_visible_row);
2386 vert_scrollbar.Value = first_visible_row;
2390 private void SetDataSource (object source, string member)
2392 SetDataSource (source, member, true);
2395 bool in_setdatasource;
2396 private void SetDataSource (object source, string member, bool recreate_rows)
2398 CurrencyManager old_lm = list_manager;
2400 /* we need this bool flag to work around a
2401 * problem with OnBindingContextChanged. once
2402 * that stuff works properly, remove this
2404 if (in_setdatasource)
2406 in_setdatasource = true;
2409 if (datasource == source && member == datamember)
2413 if (source != null && source as IListSource != null && source as IList != null)
2414 throw new Exception ("Wrong complex data binding source");
2416 datasource = source;
2417 datamember = member;
2422 current_cell = new DataGridCell ();
2424 if (list_manager != null)
2425 DisconnectListManagerEvents ();
2427 list_manager = null;
2429 /* create the new list manager */
2430 if (BindingContext != null && datasource != null)
2431 list_manager = (CurrencyManager) BindingContext [datasource, datamember];
2433 if (list_manager != null)
2434 ConnectListManagerEvents ();
2436 if (old_lm != list_manager) {
2439 /* reset first_visible_row to 0 here before
2440 * doing anything that'll requires us to
2441 * figure out if we need a scrollbar. */
2442 vert_scrollbar.Value = 0;
2443 horiz_scrollbar.Value = 0;
2444 first_visible_row = 0;
2447 RecreateDataGridRows (false);
2450 CalcAreasAndInvalidate ();
2452 in_setdatasource = false;
2454 OnDataSourceChanged (EventArgs.Empty);
2457 void RecreateDataGridRows (bool recalc)
2459 DataGridRelationshipRow[] new_rows = new DataGridRelationshipRow[RowsCount + (ShowEditRow ? 1 : 0)];
2460 int start_index = 0;
2462 start_index = rows.Length;
2463 Array.Copy (rows, 0, new_rows, 0, rows.Length < new_rows.Length ? rows.Length : new_rows.Length);
2466 for (int i = start_index; i < new_rows.Length; i ++) {
2467 new_rows[i] = new DataGridRelationshipRow (this);
2468 new_rows[i].height = RowHeight;
2470 new_rows[i].VerticalOffset = new_rows[i-1].VerticalOffset + new_rows[i-1].Height;
2474 // UIA Framework event: Updates collection list depending on binding
2475 CollectionChangeAction action = CollectionChangeAction.Refresh;
2477 if (new_rows.Length - rows.Length > 0)
2478 action = CollectionChangeAction.Add;
2480 action = CollectionChangeAction.Remove;
2486 CalcAreasAndInvalidate ();
2488 // UIA Framework event: Row added/removed
2489 OnUIACollectionChangedEvent (new CollectionChangeEventArgs (action, -1));
2493 internal void UpdateRowsFrom (DataGridRelationshipRow row)
2495 int start_index = Array.IndexOf (rows, row);
2496 if (start_index == -1)
2499 for (int i = start_index + 1; i < rows.Length; i ++)
2500 rows[i].VerticalOffset = rows[i-1].VerticalOffset + rows[i-1].Height;
2502 CalcAreasAndInvalidate ();
2507 if (list_manager != null) {
2508 string list_name = list_manager.GetListName (null);
2509 if (TableStyles[list_name] == null) {
2510 // no style exists by the supplied name
2511 current_style.GridColumnStyles.Clear ();
2512 current_style.CreateColumnsForTable (false);
2513 } else if (CurrentTableStyle == grid_style ||
2514 CurrentTableStyle.MappingName != list_name) {
2515 // If the style has been defined by the user, use it
2516 // Also, if the user provided style is empty,
2517 // force a bind for it
2518 CurrentTableStyle = styles_collection[list_name];
2519 current_style.CreateColumnsForTable (current_style.GridColumnStyles.Count > 0);
2521 current_style.CreateColumnsForTable (true);
2524 current_style.CreateColumnsForTable (false);
2527 private void OnListManagerMetaDataChanged (object sender, EventArgs e)
2530 CalcAreasAndInvalidate ();
2533 private void OnListManagerPositionChanged (object sender, EventArgs e)
2535 // Set the field directly, as we are empty now and using CurrentRow
2536 // directly would add a new row in this case.
2537 if (list_manager.Count == 0) {
2538 current_cell = new DataGridCell (0, 0);
2542 from_positionchanged_handler = true;
2543 CurrentRow = list_manager.Position;
2544 from_positionchanged_handler = false;
2547 private void OnListManagerItemChanged (object sender, ItemChangedEventArgs e)
2549 // if it was us who created the new row in CurrentCell, ignore it and don't recreate the rows yet.
2553 if (e.Index == -1) {
2555 if (rows == null || RowsCount != rows.Length - (ShowEditRow ? 1 : 0))
2556 RecreateDataGridRows (true);
2558 InvalidateRow (e.Index);
2562 private void OnTableStylesCollectionChanged (object sender, CollectionChangeEventArgs e)
2564 if (ListManager == null)
2567 string list_name = ListManager.GetListName (null);
2569 case CollectionChangeAction.Add:
2570 if (e.Element != null && String.Compare (list_name, ((DataGridTableStyle)e.Element).MappingName, true) == 0) {
2571 CurrentTableStyle = (DataGridTableStyle)e.Element;
2572 // force to auto detect columns in case the new style is completely empty
2573 ((DataGridTableStyle) e.Element).CreateColumnsForTable (CurrentTableStyle.GridColumnStyles.Count > 0);
2576 case CollectionChangeAction.Remove:
2577 if (e.Element != null && String.Compare (list_name, ((DataGridTableStyle)e.Element).MappingName, true) == 0) {
2578 CurrentTableStyle = default_style;
2579 current_style.GridColumnStyles.Clear ();
2580 current_style.CreateColumnsForTable (false);
2583 case CollectionChangeAction.Refresh:
2584 if (CurrentTableStyle == default_style
2585 || String.Compare (list_name, CurrentTableStyle.MappingName, true) != 0) {
2586 DataGridTableStyle style = styles_collection [list_name];
2587 if (style != null) {
2588 CurrentTableStyle = style;
2589 current_style.CreateColumnsForTable (false);
2591 CurrentTableStyle = default_style;
2592 current_style.GridColumnStyles.Clear ();
2593 current_style.CreateColumnsForTable (false);
2598 CalcAreasAndInvalidate ();
2601 private void AddNewRow ()
2603 ListManager.EndCurrentEdit ();
2604 ListManager.AddNew ();
2607 private void Edit ()
2609 if (CurrentTableStyle.GridColumnStyles.Count == 0)
2612 if (!CurrentTableStyle.GridColumnStyles[CurrentColumn].bound)
2615 // if we don't have any rows nor the "new" cell, there's nothing to do
2616 if (ListManager != null && (ListManager.Count == 0 && !ListManager.AllowNew))
2620 is_changing = false;
2622 CurrentTableStyle.GridColumnStyles[CurrentColumn].Edit (ListManager,
2623 CurrentRow, GetCellBounds (CurrentRow, CurrentColumn),
2624 _readonly, null, true);
2627 private void EndEdit ()
2629 if (CurrentTableStyle.GridColumnStyles.Count == 0)
2632 if (!CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber].bound)
2635 EndEdit (CurrentTableStyle.GridColumnStyles[current_cell.ColumnNumber],
2636 current_cell.RowNumber, false);
2639 private void ShiftSelection (int index)
2641 // we have to save off selection_start
2642 // because ResetSelection clobbers it
2643 int saved_selection_start = selection_start;
2647 selection_start = saved_selection_start;
2649 if (index >= selection_start) {
2650 start = selection_start;
2654 end = selection_start;
2657 if (start == -1) start = 0;
2659 for (int idx = start; idx <= end; idx ++)
2663 private void ScrollToColumnInPixels (int pixel)
2667 if (pixel > horiz_pixeloffset) // ScrollRight
2668 pixels = -1 * (pixel - horiz_pixeloffset);
2670 pixels = horiz_pixeloffset - pixel;
2672 Rectangle area = cells_area;
2674 if (ColumnHeadersVisible) {
2675 area.Y -= ColumnHeadersArea.Height;
2676 area.Height += ColumnHeadersArea.Height;
2679 horiz_pixeloffset = pixel;
2680 UpdateVisibleColumn ();
2684 XplatUI.ScrollWindow (Handle, area, pixels, 0, false);
2686 int pixel_offset = GetColumnStartingPixel (CurrentColumn);
2687 int next_pixel_offset = pixel_offset + CurrentTableStyle.GridColumnStyles[CurrentColumn].Width;
2689 if (pixel_offset >= horiz_pixeloffset
2690 && next_pixel_offset < horiz_pixeloffset + cells_area.Width)
2694 private void ScrollToRow (int old_row, int new_row)
2699 if (new_row > old_row) { // Scrolldown
2700 for (i = old_row; i < new_row; i ++)
2701 pixels -= rows[i].Height;
2703 for (i = new_row; i < old_row; i ++)
2704 pixels += rows[i].Height;
2710 Rectangle rows_area = cells_area; // Cells area - partial rows space
2712 if (RowHeadersVisible) {
2713 rows_area.X -= RowHeaderWidth;
2714 rows_area.Width += RowHeaderWidth;
2717 /* scroll the window */
2718 XplatUI.ScrollWindow (Handle, rows_area, 0, pixels, false);
2720 /* if the row is still */
2721 if (CurrentRow >= first_visible_row && CurrentRow < first_visible_row + visible_row_count)
2726 private void ColumnResize (int column)
2728 CurrencyManager source = this.ListManager;
2729 DataGridColumnStyle style = CurrentTableStyle.GridColumnStyles[column];
2730 string headerText = style.HeaderText;
2731 using (Graphics g = base.CreateGraphics ()) {
2732 int rows = source.Count;
2733 int width = (int)g.MeasureString (headerText, CurrentTableStyle.HeaderFont).Width + 4;
2735 for (int i = 0; i < rows; i++) {
2736 int rowColWidth = (int)style.GetPreferredSize (g, style.GetColumnValueAtRow (source, i)).Width;
2737 if (rowColWidth > width)
2738 width = rowColWidth;
2740 if (style.Width != width)
2741 style.Width = width;
2745 private void RowResize (int row)
2747 CurrencyManager source = this.ListManager;
2748 using (Graphics g = base.CreateGraphics ()) {
2749 GridColumnStylesCollection columns = CurrentTableStyle.GridColumnStyles;
2750 int colCount = columns.Count;
2751 //int rowCount = source.Count;
2753 for (int i = 0; i < colCount; i++) {
2754 object val = columns[i].GetColumnValueAtRow (source, row);
2755 height = Math.Max (columns[i].GetPreferredHeight (g, val), height);
2757 if (this.DataGridRows[row].Height != height)
2758 this.DataGridRows[row].Height = height;
2761 #endregion Private Instance Methods
2764 static object AllowNavigationChangedEvent = new object ();
2765 static object BackButtonClickEvent = new object ();
2766 static object BackgroundColorChangedEvent = new object ();
2767 static object BorderStyleChangedEvent = new object ();
2768 static object CaptionVisibleChangedEvent = new object ();
2769 static object CurrentCellChangedEvent = new object ();
2770 static object DataSourceChangedEvent = new object ();
2771 static object FlatModeChangedEvent = new object ();
2772 static object NavigateEvent = new object ();
2773 static object ParentRowsLabelStyleChangedEvent = new object ();
2774 static object ParentRowsVisibleChangedEvent = new object ();
2775 static object ReadOnlyChangedEvent = new object ();
2776 static object RowHeaderClickEvent = new object ();
2777 static object ScrollEvent = new object ();
2778 static object ShowParentDetailsButtonClickEvent = new object ();
2780 public event EventHandler AllowNavigationChanged {
2781 add { Events.AddHandler (AllowNavigationChangedEvent, value); }
2782 remove { Events.RemoveHandler (AllowNavigationChangedEvent, value); }
2785 public event EventHandler BackButtonClick {
2786 add { Events.AddHandler (BackButtonClickEvent, value); }
2787 remove { Events.RemoveHandler (BackButtonClickEvent, value); }
2790 public event EventHandler BackgroundColorChanged {
2791 add { Events.AddHandler (BackgroundColorChangedEvent, value); }
2792 remove { Events.RemoveHandler (BackgroundColorChangedEvent, value); }
2796 [EditorBrowsable(EditorBrowsableState.Never)]
2797 public new event EventHandler BackgroundImageChanged {
2798 add { base.BackgroundImageChanged += value; }
2799 remove { base.BackgroundImageChanged -= value; }
2804 [EditorBrowsable(EditorBrowsableState.Never)]
2805 public new event EventHandler BackgroundImageLayoutChanged {
2806 add { base.BackgroundImageLayoutChanged += value; }
2807 remove { base.BackgroundImageLayoutChanged -= value; }
2812 [EditorBrowsable(EditorBrowsableState.Never)]
2813 public new event EventHandler TextChanged {
2814 add { base.TextChanged += value; }
2815 remove { base.TextChanged -= value; }
2819 [EditorBrowsable(EditorBrowsableState.Never)]
2820 public new event EventHandler CursorChanged {
2821 add { base.CursorChanged += value; }
2822 remove { base.CursorChanged -= value; }
2825 public event EventHandler BorderStyleChanged {
2826 add { Events.AddHandler (BorderStyleChangedEvent, value); }
2827 remove { Events.RemoveHandler (BorderStyleChangedEvent, value); }
2830 public event EventHandler CaptionVisibleChanged {
2831 add { Events.AddHandler (CaptionVisibleChangedEvent, value); }
2832 remove { Events.RemoveHandler (CaptionVisibleChangedEvent, value); }
2835 public event EventHandler CurrentCellChanged {
2836 add { Events.AddHandler (CurrentCellChangedEvent, value); }
2837 remove { Events.RemoveHandler (CurrentCellChangedEvent, value); }
2840 public event EventHandler DataSourceChanged {
2841 add { Events.AddHandler (DataSourceChangedEvent, value); }
2842 remove { Events.RemoveHandler (DataSourceChangedEvent, value); }
2845 public event EventHandler FlatModeChanged {
2846 add { Events.AddHandler (FlatModeChangedEvent, value); }
2847 remove { Events.RemoveHandler (FlatModeChangedEvent, value); }
2850 public event NavigateEventHandler Navigate {
2851 add { Events.AddHandler (NavigateEvent, value); }
2852 remove { Events.RemoveHandler (NavigateEvent, value); }
2855 public event EventHandler ParentRowsLabelStyleChanged {
2856 add { Events.AddHandler (ParentRowsLabelStyleChangedEvent, value); }
2857 remove { Events.RemoveHandler (ParentRowsLabelStyleChangedEvent, value); }
2860 public event EventHandler ParentRowsVisibleChanged {
2861 add { Events.AddHandler (ParentRowsVisibleChangedEvent, value); }
2862 remove { Events.RemoveHandler (ParentRowsVisibleChangedEvent, value); }
2865 public event EventHandler ReadOnlyChanged {
2866 add { Events.AddHandler (ReadOnlyChangedEvent, value); }
2867 remove { Events.RemoveHandler (ReadOnlyChangedEvent, value); }
2870 protected event EventHandler RowHeaderClick {
2871 add { Events.AddHandler (RowHeaderClickEvent, value); }
2872 remove { Events.RemoveHandler (RowHeaderClickEvent, value); }
2875 public event EventHandler Scroll {
2876 add { Events.AddHandler (ScrollEvent, value); }
2877 remove { Events.RemoveHandler (ScrollEvent, value); }
2880 public event EventHandler ShowParentDetailsButtonClick {
2881 add { Events.AddHandler (ShowParentDetailsButtonClickEvent, value); }
2882 remove { Events.RemoveHandler (ShowParentDetailsButtonClickEvent, value); }
2884 #endregion // Events
2886 #region Code originally in DataGridDrawingLogic.cs
2888 #region Local Variables
2891 Rectangle parent_rows;
2892 int width_of_all_columns;
2894 internal Rectangle caption_area;
2895 internal Rectangle column_headers_area; // Used columns header area
2896 internal int column_headers_max_width; // Total width (max width) for columns headrs
2897 internal Rectangle row_headers_area; // Used Headers rows area
2898 internal Rectangle cells_area;
2899 #endregion // Local Variables
2901 #region Public Instance Methods
2903 // Calc the max with of all columns
2904 private int CalcAllColumnsWidth ()
2907 int cnt = CurrentTableStyle.GridColumnStyles.Count;
2909 for (int col = 0; col < cnt; col++) {
2910 if (CurrentTableStyle.GridColumnStyles[col].bound == false) {
2913 width += CurrentTableStyle.GridColumnStyles[col].Width;
2918 // Gets a column from a pixel
2919 private int FromPixelToColumn (int pixel, out int column_x)
2922 int cnt = CurrentTableStyle.GridColumnStyles.Count;
2928 if (CurrentTableStyle.CurrentRowHeadersVisible) {
2929 width += row_headers_area.X + row_headers_area.Width;
2930 column_x += row_headers_area.X + row_headers_area.Width;
2935 for (int col = 0; col < cnt; col++) {
2936 if (CurrentTableStyle.GridColumnStyles[col].bound == false)
2939 width += CurrentTableStyle.GridColumnStyles[col].Width;
2944 column_x += CurrentTableStyle.GridColumnStyles[col].Width;
2950 internal int GetColumnStartingPixel (int my_col)
2953 int cnt = CurrentTableStyle.GridColumnStyles.Count;
2955 for (int col = 0; col < cnt; col++) {
2956 if (CurrentTableStyle.GridColumnStyles[col].bound == false) {
2963 width += CurrentTableStyle.GridColumnStyles[col].Width;
2969 // Which column has to be the first visible column to ensure a column visibility
2970 int GetFirstColumnForColumnVisibility (int current_first_visible_column, int column)
2972 int new_col = column;
2975 if (column > current_first_visible_column) { // Going forward
2976 for (new_col = column; new_col >= 0; new_col--) {
2977 if (!CurrentTableStyle.GridColumnStyles[new_col].bound)
2979 width += CurrentTableStyle.GridColumnStyles[new_col].Width;
2981 if (width >= cells_area.Width)
2983 //return new_col < CurrentTableStyle.GridColumnStyles.Count ? new_col + 1 : CurrentTableStyle.GridColumnStyles.Count;
2991 bool in_calc_grid_areas;
2992 void CalcGridAreas ()
2994 if (!IsHandleCreated) // Delay calculations until the handle is created
2997 /* make sure we don't happen to end up in this method again */
2998 if (in_calc_grid_areas)
3001 in_calc_grid_areas = true;
3003 /* Order is important. E.g. row headers max. height depends on caption */
3004 horiz_pixeloffset = 0;
3007 CalcParentButtons ();
3008 UpdateVisibleRowCount ();
3010 width_of_all_columns = CalcAllColumnsWidth ();
3011 CalcColumnHeaders ();
3014 bool needHoriz = false;
3015 bool needVert = false;
3017 /* figure out which scrollbars we need, and what the visible areas are */
3018 int visible_cells_width = cells_area.Width;
3019 int visible_cells_height = cells_area.Height;
3020 int allrows = RowsCount;
3022 if (ShowEditRow && RowsCount > 0)
3025 /* use a loop to iteratively calculate whether
3026 * we need horiz/vert scrollbars. */
3027 for (int i = 0; i < 3; i++) {
3029 visible_cells_width = cells_area.Width - vert_scrollbar.Width;
3031 visible_cells_height = cells_area.Height - horiz_scrollbar.Height;
3033 UpdateVisibleRowCount ();
3035 needHoriz = (width_of_all_columns > visible_cells_width);
3036 needVert = (allrows > MaxVisibleRowCount);
3039 int horiz_scrollbar_width = ClientRectangle.Width;
3040 int horiz_scrollbar_maximum = 0;
3041 int vert_scrollbar_height = 0;
3042 int vert_scrollbar_maximum = 0;
3045 SetUpVerticalScrollBar (out vert_scrollbar_height, out vert_scrollbar_maximum);
3048 SetUpHorizontalScrollBar (out horiz_scrollbar_maximum);
3050 cells_area.Width = visible_cells_width;
3051 cells_area.Height = visible_cells_height;
3053 if (needVert && needHoriz) {
3055 parent_rows.Width -= vert_scrollbar.Width;
3057 if (!ColumnHeadersVisible) {
3058 if (column_headers_area.X + column_headers_area.Width > vert_scrollbar.Location.X) {
3059 column_headers_area.Width -= vert_scrollbar.Width;
3063 horiz_scrollbar_width -= vert_scrollbar.Width;
3064 vert_scrollbar_height -= horiz_scrollbar.Height;
3068 if (row_headers_area.Y + row_headers_area.Height > ClientRectangle.Y + ClientRectangle.Height) {
3069 row_headers_area.Height -= horiz_scrollbar.Height;
3072 vert_scrollbar.Size = new Size (vert_scrollbar.Width,
3073 vert_scrollbar_height);
3075 vert_scrollbar.Maximum = vert_scrollbar_maximum;
3076 Controls.Add (vert_scrollbar);
3077 vert_scrollbar.Visible = true;
3079 Controls.Remove (vert_scrollbar);
3080 vert_scrollbar.Visible = false;
3084 horiz_scrollbar.Size = new Size (horiz_scrollbar_width,
3085 horiz_scrollbar.Height);
3087 horiz_scrollbar.Maximum = horiz_scrollbar_maximum;
3088 Controls.Add (horiz_scrollbar);
3089 horiz_scrollbar.Visible = true;
3091 Controls.Remove (horiz_scrollbar);
3092 horiz_scrollbar.Visible = false;
3095 UpdateVisibleColumn ();
3096 UpdateVisibleRowCount ();
3098 in_calc_grid_areas = false;
3103 caption_area.X = ClientRectangle.X;
3104 caption_area.Y = ClientRectangle.Y;
3105 caption_area.Width = ClientRectangle.Width;
3106 if (caption_visible) {
3107 caption_area.Height = CaptionFont.Height;
3108 if (caption_area.Height < back_button_image.Height)
3109 caption_area.Height = back_button_image.Height;
3110 caption_area.Height += 2;
3112 caption_area.Height = 0;
3115 void CalcCellsArea ()
3117 cells_area.X = ClientRectangle.X + row_headers_area.Width;
3118 cells_area.Y = column_headers_area.Y + column_headers_area.Height;
3119 cells_area.Width = ClientRectangle.X + ClientRectangle.Width - cells_area.X;
3120 if (cells_area.Width < 0)
3121 cells_area.Width = 0;
3122 cells_area.Height = ClientRectangle.Y + ClientRectangle.Height - cells_area.Y;
3123 if (cells_area.Height < 0)
3124 cells_area.Height = 0;
3127 void CalcColumnHeaders ()
3131 column_headers_area.X = ClientRectangle.X;
3132 column_headers_area.Y = parent_rows.Y + parent_rows.Height;
3134 // TODO: take into account Scrollbars
3135 column_headers_max_width = ClientRectangle.X + ClientRectangle.Width - column_headers_area.X;
3136 max_width_cols = column_headers_max_width;
3138 if (CurrentTableStyle.CurrentRowHeadersVisible)
3139 max_width_cols -= RowHeaderWidth;
3141 if (width_of_all_columns > max_width_cols) {
3142 column_headers_area.Width = column_headers_max_width;
3144 column_headers_area.Width = width_of_all_columns;
3146 if (CurrentTableStyle.CurrentRowHeadersVisible)
3147 column_headers_area.Width += RowHeaderWidth;
3150 if (ColumnHeadersVisible)
3151 column_headers_area.Height = CurrentTableStyle.HeaderFont.Height + 6;
3153 column_headers_area.Height = 0;
3156 void CalcParentRows ()
3158 parent_rows.X = ClientRectangle.X;
3159 parent_rows.Y = caption_area.Y + caption_area.Height;
3160 parent_rows.Width = ClientRectangle.Width;
3162 parent_rows.Height = (CaptionFont.Height + 3) * data_source_stack.Count;
3164 parent_rows.Height = 0;
3167 void CalcParentButtons ()
3169 if (data_source_stack.Count > 0 && CaptionVisible) {
3170 back_button_rect = new Rectangle (ClientRectangle.X + ClientRectangle.Width - 2 * (caption_area.Height - 2) - 8,
3171 caption_area.Height / 2 - back_button_image.Height / 2,
3172 back_button_image.Width, back_button_image.Height);
3173 parent_rows_button_rect = new Rectangle (ClientRectangle.X + ClientRectangle.Width - (caption_area.Height - 2) - 4,
3174 caption_area.Height / 2 - parent_rows_button_image.Height / 2,
3175 parent_rows_button_image.Width, parent_rows_button_image.Height);
3177 back_button_rect = parent_rows_button_rect = Rectangle.Empty;
3181 void CalcRowHeaders ()
3183 row_headers_area.X = ClientRectangle.X;
3184 row_headers_area.Y = column_headers_area.Y + column_headers_area.Height;
3185 row_headers_area.Height = ClientRectangle.Height + ClientRectangle.Y - row_headers_area.Y;
3187 if (CurrentTableStyle.CurrentRowHeadersVisible)
3188 row_headers_area.Width = RowHeaderWidth;
3190 row_headers_area.Width = 0;
3193 int GetVisibleRowCount (int visibleHeight)
3195 int rows_height = 0;
3197 for (r = FirstVisibleRow; r < rows.Length; r ++) {
3198 if (rows_height + rows[r].Height >= visibleHeight)
3200 rows_height += rows[r].Height;
3203 if (r <= rows.Length - 1)
3206 return r - FirstVisibleRow;
3209 void UpdateVisibleColumn ()
3211 visible_column_count = 0;
3213 if (CurrentTableStyle.GridColumnStyles.Count == 0)
3221 min_pixel = horiz_pixeloffset;
3222 if (CurrentTableStyle.CurrentRowHeadersVisible)
3223 min_pixel += row_headers_area.X + row_headers_area.Width;
3224 max_pixel = min_pixel + cells_area.Width;
3226 first_visible_column = FromPixelToColumn (min_pixel, out unused);
3227 max_col = FromPixelToColumn (max_pixel, out unused);
3229 for (int i = first_visible_column; i <= max_col; i ++) {
3230 if (CurrentTableStyle.GridColumnStyles[i].bound)
3231 visible_column_count++;
3234 if (first_visible_column + visible_column_count < CurrentTableStyle.GridColumnStyles.Count) {
3235 visible_column_count++; // Partially visible column
3239 void UpdateVisibleRowCount ()
3241 visible_row_count = GetVisibleRowCount (cells_area.Height);
3243 CalcRowHeaders (); // Height depends on num of visible rows
3246 void InvalidateCaption ()
3248 if (caption_area.IsEmpty)
3251 Invalidate (caption_area);
3254 void InvalidateRow (int row)
3256 if (row < FirstVisibleRow || row > FirstVisibleRow + VisibleRowCount)
3259 Rectangle rect_row = new Rectangle ();
3261 rect_row.X = cells_area.X;
3262 rect_row.Width = width_of_all_columns;
3263 if (rect_row.Width > cells_area.Width)
3264 rect_row.Width = cells_area.Width;
3265 rect_row.Height = rows[row].Height;
3266 rect_row.Y = cells_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
3267 Invalidate (rect_row);
3270 void InvalidateRowHeader (int row)
3272 Rectangle rect_rowhdr = new Rectangle ();
3273 rect_rowhdr.X = row_headers_area.X;
3274 rect_rowhdr.Width = row_headers_area.Width;
3275 rect_rowhdr.Height = rows[row].Height;
3276 rect_rowhdr.Y = row_headers_area.Y + rows[row].VerticalOffset - rows[FirstVisibleRow].VerticalOffset;
3277 Invalidate (rect_rowhdr);
3280 internal void InvalidateColumn (DataGridColumnStyle column)
3282 Rectangle rect_col = new Rectangle ();
3286 col = CurrentTableStyle.GridColumnStyles.IndexOf (column);
3291 rect_col.Width = column.Width;
3292 col_pixel = GetColumnStartingPixel (col);
3293 rect_col.X = cells_area.X + col_pixel - horiz_pixeloffset;
3294 rect_col.Y = cells_area.Y;
3295 rect_col.Height = cells_area.Height;
3296 Invalidate (rect_col);
3299 void DrawResizeLineVert (int x)
3301 XplatUI.DrawReversibleRectangle (Handle,
3302 new Rectangle (x, cells_area.Y, 1, cells_area.Height - 3),
3306 void DrawResizeLineHoriz (int y)
3308 XplatUI.DrawReversibleRectangle (Handle,
3309 new Rectangle (cells_area.X, y, cells_area.Width - 3, 1),
3313 void SetUpHorizontalScrollBar (out int maximum)
3315 maximum = width_of_all_columns;
3317 horiz_scrollbar.Location = new Point (ClientRectangle.X, ClientRectangle.Y +
3318 ClientRectangle.Height - horiz_scrollbar.Height);
3320 horiz_scrollbar.LargeChange = cells_area.Width;
3323 void SetUpVerticalScrollBar (out int height, out int maximum)
3327 y = ClientRectangle.Y + parent_rows.Y + parent_rows.Height;
3328 height = ClientRectangle.Height - parent_rows.Y - parent_rows.Height;
3330 vert_scrollbar.Location = new Point (ClientRectangle.X +
3331 ClientRectangle.Width - vert_scrollbar.Width, y);
3333 maximum = RowsCount;
3335 if (ShowEditRow && RowsCount > 0) {
3339 vert_scrollbar.LargeChange = VLargeChange;
3342 #endregion // Public Instance Methods
3344 #region Instance Properties
3345 // Returns the ColumnHeaders area excluding the rectangle shared with RowHeaders
3346 internal Rectangle ColumnHeadersArea {
3348 Rectangle columns_area = column_headers_area;
3350 if (CurrentTableStyle.CurrentRowHeadersVisible) {
3351 columns_area.X += RowHeaderWidth;
3352 columns_area.Width -= RowHeaderWidth;
3354 return columns_area;
3358 internal Rectangle RowHeadersArea {
3359 get { return row_headers_area; }
3362 internal Rectangle ParentRowsArea {
3363 get { return parent_rows; }
3368 return MaxVisibleRowCount;
3372 #endregion Instance Properties
3374 #endregion // Code originally in DataGridDrawingLogic.cs
3378 #region UIA Framework: Methods, Properties and Events
3380 static object UIACollectionChangedEvent = new object ();
3381 static object UIASelectionChangedEvent = new object ();
3382 static object UIAColumnHeadersVisibleChangedEvent = new object ();
3383 static object UIAGridCellChangedEvent = new object ();
3385 internal ScrollBar UIAHScrollBar {
3386 get { return horiz_scrollbar; }
3389 internal ScrollBar UIAVScrollBar {
3390 get { return vert_scrollbar; }
3393 internal DataGridTableStyle UIACurrentTableStyle {
3394 get { return current_style; }
3397 internal int UIASelectedRows {
3398 get { return selected_rows.Count; }
3401 internal Rectangle UIAColumnHeadersArea {
3402 get { return ColumnHeadersArea; }
3405 internal Rectangle UIACaptionArea {
3406 get { return caption_area; }
3409 internal Rectangle UIACellsArea {
3410 get { return cells_area; }
3413 internal int UIARowHeight {
3414 get { return RowHeight; }
3417 internal event CollectionChangeEventHandler UIACollectionChanged {
3418 add { Events.AddHandler (UIACollectionChangedEvent, value); }
3419 remove { Events.RemoveHandler (UIACollectionChangedEvent, value); }
3422 internal event CollectionChangeEventHandler UIASelectionChanged {
3423 add { Events.AddHandler (UIASelectionChangedEvent, value); }
3424 remove { Events.RemoveHandler (UIASelectionChangedEvent, value); }
3427 internal event EventHandler UIAColumnHeadersVisibleChanged {
3428 add { Events.AddHandler (UIAColumnHeadersVisibleChangedEvent, value); }
3429 remove { Events.RemoveHandler (UIAColumnHeadersVisibleChangedEvent, value); }
3432 internal event CollectionChangeEventHandler UIAGridCellChanged {
3433 add { Events.AddHandler (UIAGridCellChangedEvent, value); }
3434 remove { Events.RemoveHandler (UIAGridCellChangedEvent, value); }
3437 internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args)
3439 CollectionChangeEventHandler eh
3440 = (CollectionChangeEventHandler) Events [UIACollectionChangedEvent];
3445 internal void OnUIASelectionChangedEvent (CollectionChangeEventArgs args)
3447 CollectionChangeEventHandler eh
3448 = (CollectionChangeEventHandler) Events [UIASelectionChangedEvent];
3453 internal void OnUIAColumnHeadersVisibleChanged ()
3455 EventHandler eh = (EventHandler) Events [UIAColumnHeadersVisibleChangedEvent];
3457 eh (this, EventArgs.Empty);
3460 internal void OnUIAGridCellChanged (CollectionChangeEventArgs args)
3462 CollectionChangeEventHandler eh
3463 = (CollectionChangeEventHandler) Events [UIAGridCellChangedEvent];
3468 #endregion // UIA Framework: Methods, Properties and Events