X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FManaged.Windows.Forms%2FSystem.Windows.Forms%2FDataGridView.cs;h=3f766d3eb01f01c462da2825d4cb66a9a6656b20;hb=b55f4ec257741ce00eaf78029ea8c60a7a61f085;hp=da4e8cdebf3e9e66b5765bf072fcf183b5ccbce1;hpb=3fa0c3ef8c98320bbfe82a836417fc659e5d6856;p=mono.git diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/DataGridView.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/DataGridView.cs index da4e8cdebf3..3f766d3eb01 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/DataGridView.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/DataGridView.cs @@ -81,7 +81,7 @@ namespace System.Windows.Forms { private DataGridViewCellStyle defaultCellStyle; //private Control editingControl; private DataGridViewEditMode editMode; - private bool enableHeadersVisualStyles; + private bool enableHeadersVisualStyles = true; private DataGridViewCell firstDisplayedCell; private int firstDisplayedScrollingColumnHiddenWidth; private int firstDisplayedScrollingColumnIndex; @@ -117,7 +117,8 @@ namespace System.Windows.Forms { private HScrollBar horizontalScrollBar; private VScrollBar verticalScrollBar; private Control editingControl; - + private bool new_row_commited = true; + // These are used to implement selection behaviour with SHIFT pressed. private int selected_row = -1; private int selected_column = -1; @@ -134,6 +135,16 @@ namespace System.Windows.Forms { private int gridWidth; private int gridHeight; + DataGridViewHeaderCell pressed_header_cell; + DataGridViewHeaderCell entered_header_cell; + + // For column/row resizing via mouse + private bool column_resize_active = false; + private bool row_resize_active = false; + private int resize_band = -1; + private int resize_band_start = 0; + private int resize_band_delta = 0; + public DataGridView () { SetStyle (ControlStyles.Opaque, true); @@ -160,7 +171,7 @@ namespace System.Windows.Forms { backColor = Control.DefaultBackColor; backgroundColor = SystemColors.AppWorkspace; borderStyle = BorderStyle.FixedSingle; - cellBorderStyle = DataGridViewCellBorderStyle.None; + cellBorderStyle = DataGridViewCellBorderStyle.Single; clipboardCopyMode = DataGridViewClipboardCopyMode.EnableWithAutoHeaderText; columnHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single; columnHeadersDefaultCellStyle = new DataGridViewCellStyle(); @@ -186,6 +197,8 @@ namespace System.Windows.Forms { defaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleLeft; defaultCellStyle.WrapMode = DataGridViewTriState.False; editMode = DataGridViewEditMode.EditOnKeystrokeOrF2; + firstDisplayedScrollingColumnHiddenWidth = 0; + isCurrentCellDirty = false; multiSelect = true; readOnly = false; rowHeadersBorderStyle = DataGridViewHeaderBorderStyle.Single; @@ -380,7 +393,13 @@ namespace System.Windows.Forms { throw new InvalidOperationException("Cant set this property to AllHeaders or DisplayedHeaders in this DataGridView."); } autoSizeRowsMode = value; - AutoResizeRows (value); + + if (value == DataGridViewAutoSizeRowsMode.None) + foreach (DataGridViewRow row in Rows) + row.ResetToExplicitHeight (); + else + AutoResizeRows (value); + OnAutoSizeRowsModeChanged(new DataGridViewAutoSizeModeEventArgs(false)); Invalidate (); //////////////////////////////////////////////////////////////// @@ -467,8 +486,60 @@ namespace System.Windows.Forms { get { return cellBorderStyle; } set { if (cellBorderStyle != value) { + if (value == DataGridViewCellBorderStyle.Custom) + throw new ArgumentException ("CellBorderStyle cannot be set to Custom."); + cellBorderStyle = value; - OnCellBorderStyleChanged(EventArgs.Empty); + + DataGridViewAdvancedBorderStyle border = new DataGridViewAdvancedBorderStyle (); + + switch (cellBorderStyle) { + case DataGridViewCellBorderStyle.Single: + border.All = DataGridViewAdvancedCellBorderStyle.Single; + break; + case DataGridViewCellBorderStyle.Raised: + case DataGridViewCellBorderStyle.RaisedVertical: + border.Bottom = DataGridViewAdvancedCellBorderStyle.None; + border.Top = DataGridViewAdvancedCellBorderStyle.None; + border.Left = DataGridViewAdvancedCellBorderStyle.Outset; + border.Right = DataGridViewAdvancedCellBorderStyle.Outset; + break; + case DataGridViewCellBorderStyle.Sunken: + border.All = DataGridViewAdvancedCellBorderStyle.Inset; + break; + case DataGridViewCellBorderStyle.None: + border.All = DataGridViewAdvancedCellBorderStyle.None; + break; + case DataGridViewCellBorderStyle.SingleVertical: + border.Bottom = DataGridViewAdvancedCellBorderStyle.None; + border.Top = DataGridViewAdvancedCellBorderStyle.None; + border.Left = DataGridViewAdvancedCellBorderStyle.None; + border.Right = DataGridViewAdvancedCellBorderStyle.Single; + break; + case DataGridViewCellBorderStyle.SunkenVertical: + border.Bottom = DataGridViewAdvancedCellBorderStyle.None; + border.Top = DataGridViewAdvancedCellBorderStyle.None; + border.Left = DataGridViewAdvancedCellBorderStyle.Inset; + border.Right = DataGridViewAdvancedCellBorderStyle.Inset; + break; + case DataGridViewCellBorderStyle.SingleHorizontal: + case DataGridViewCellBorderStyle.SunkenHorizontal: + border.Bottom = DataGridViewAdvancedCellBorderStyle.Inset; + border.Top = DataGridViewAdvancedCellBorderStyle.Inset; + border.Left = DataGridViewAdvancedCellBorderStyle.None; + border.Right = DataGridViewAdvancedCellBorderStyle.None; + break; + case DataGridViewCellBorderStyle.RaisedHorizontal: + border.Bottom = DataGridViewAdvancedCellBorderStyle.Outset; + border.Top = DataGridViewAdvancedCellBorderStyle.Outset; + border.Left = DataGridViewAdvancedCellBorderStyle.None; + border.Right = DataGridViewAdvancedCellBorderStyle.None; + break; + } + + advancedCellBorderStyle = border; + + OnCellBorderStyleChanged (EventArgs.Empty); } } } @@ -597,11 +668,13 @@ namespace System.Windows.Forms { /// to the data cache, or the new cell is in a hidden /// row. ///////////////////////////////////////////////////// - if (value.DataGridView != this) { + if (value.DataGridView != this) throw new ArgumentException("The cell is not in this DataGridView."); - } - currentCell = value; - currentRow = currentCell.OwningRow; + + if (value != null) + MoveCurrentCell (value.OwningColumn.Index, value.OwningRow.Index, true, false, false, true); + else + MoveCurrentCell (-1, -1, true, false, false, true); } } @@ -612,7 +685,11 @@ namespace System.Windows.Forms { [Browsable (false)] public DataGridViewRow CurrentRow { - get { return currentRow; } + get { + if (currentCell != null) + return currentCell.OwningRow; + return null; + } } [DefaultValue ("")] @@ -637,24 +714,21 @@ namespace System.Windows.Forms { public object DataSource { get { return dataSource; } set { - if (dataSource != value) { - /* The System.Windows.Forms.DataGridView class supports the standard Windows Forms data-binding model. This means the data source can be of any type that implements: - - the System.Collections.IList interface, including one-dimensional arrays. - - the System.ComponentModel.IListSource interface, such as the System.Data.DataTable and System.Data.DataSet classes. - - the System.ComponentModel.IBindingList interface, such as the System.ComponentModel.Collections.BindingList<> class. - - the System.ComponentModel.IBindingListView interface, such as the System.Windows.Forms.BindingSource class. - */ - if (!(value == null || value is IList || value is IListSource || value is IBindingList || value is IBindingListView)) { - throw new NotSupportedException("Type cant be binded."); - } - - ClearBinding (); - - dataSource = value; - OnDataSourceChanged (EventArgs.Empty); + /* The System.Windows.Forms.DataGridView class supports the standard Windows Forms data-binding model. This means the data source can be of any type that implements: + - the System.Collections.IList interface, including one-dimensional arrays. + - the System.ComponentModel.IListSource interface, such as the System.Data.DataTable and System.Data.DataSet classes. + - the System.ComponentModel.IBindingList interface, such as the System.ComponentModel.Collections.BindingList<> class. + - the System.ComponentModel.IBindingListView interface, such as the System.Windows.Forms.BindingSource class. + */ + if (!(value == null || value is IList || value is IListSource || value is IBindingList || value is IBindingListView)) + throw new NotSupportedException ("Type cannot be bound."); - DoBinding (); - } + ClearBinding (); + + dataSource = value; + OnDataSourceChanged (EventArgs.Empty); + + DoBinding (); } } @@ -704,6 +778,26 @@ namespace System.Windows.Forms { set { enableHeadersVisualStyles = value; } } + internal DataGridViewHeaderCell EnteredHeaderCell { + get { return entered_header_cell; } + set { + if (entered_header_cell == value) + return; + if (ThemeEngine.Current.DataGridViewHeaderCellHasHotStyle (this)) { + Region area_to_invalidate = new Region (); + area_to_invalidate.MakeEmpty (); + if (entered_header_cell != null) + area_to_invalidate.Union (GetHeaderCellBounds (entered_header_cell)); + entered_header_cell = value; + if (entered_header_cell != null) + area_to_invalidate.Union (GetHeaderCellBounds (entered_header_cell)); + Invalidate (area_to_invalidate); + area_to_invalidate.Dispose (); + } else + entered_header_cell = value; + } + } + [Browsable (false)] [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public DataGridViewCell FirstDisplayedCell { @@ -845,7 +939,7 @@ namespace System.Windows.Forms { [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public int NewRowIndex { get { - if (!allowUserToAddRows) { + if (!allowUserToAddRows || ColumnCount == 0) { return -1; } return rows.Count - 1; @@ -860,6 +954,10 @@ namespace System.Windows.Forms { set { } } + internal DataGridViewHeaderCell PressedHeaderCell { + get { return pressed_header_cell; } + } + [Browsable (true)] [DefaultValue (false)] public bool ReadOnly { @@ -900,7 +998,7 @@ namespace System.Windows.Forms { ColumnCount = 1; for (int i = rows.Count; i < value; i++) { - DataGridViewRow row = (DataGridViewRow) RowTemplate.Clone (); + DataGridViewRow row = (DataGridViewRow) RowTemplateFull; rows.AddInternal (row, false); foreach (DataGridViewColumn col in columns) @@ -996,6 +1094,7 @@ namespace System.Windows.Forms { } } + // RowTemplate is just the row, it does not contain Cells [Browsable (true)] [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] public DataGridViewRow RowTemplate { @@ -1011,6 +1110,8 @@ namespace System.Windows.Forms { } } + // Take the RowTemplate, clone it, and add Cells + // Note this is not stored, so you don't need to Clone it internal DataGridViewRow RowTemplateFull { get { DataGridViewRow row = (DataGridViewRow) RowTemplate.Clone (); @@ -1188,6 +1289,7 @@ namespace System.Windows.Forms { get { return verticalScrollingOffset; } } + [MonoTODO ("VirtualMode is not supported.")] [EditorBrowsable (EditorBrowsableState.Advanced)] [DefaultValue (false)] public bool VirtualMode { @@ -2065,32 +2167,12 @@ namespace System.Windows.Forms { public void AutoResizeRow (int rowIndex) { - AutoResizeRow (rowIndex, DataGridViewAutoSizeRowMode.AllCells); + AutoResizeRow (rowIndex, DataGridViewAutoSizeRowMode.AllCells, true); } public void AutoResizeRow (int rowIndex, DataGridViewAutoSizeRowMode autoSizeRowMode) { - if (autoSizeRowMode == DataGridViewAutoSizeRowMode.RowHeader && !rowHeadersVisible) - throw new InvalidOperationException ("row headers are not visible"); - if (rowIndex < 0 || rowIndex > Rows.Count - 1) - throw new ArgumentOutOfRangeException ("rowIndex"); - - DataGridViewRow row = GetRowInternal (rowIndex); - - if (autoSizeRowMode == DataGridViewAutoSizeRowMode.RowHeader) { - row.Height = row.HeaderCell.PreferredSize.Height; - return; - } - - int row_height = 0; - - foreach (DataGridViewCell cell in row.Cells) - row_height = Math.Max (row_height, cell.PreferredSize.Height); - - if (autoSizeRowMode == DataGridViewAutoSizeRowMode.AllCellsExceptHeader) - row.Height = row_height; - else - row.Height = Math.Max (row_height, row.HeaderCell.PreferredSize.Height); + AutoResizeRow (rowIndex, autoSizeRowMode, true); } public void AutoResizeRowHeadersWidth (DataGridViewRowHeadersWidthSizeMode rowHeadersWidthSizeMode) @@ -2138,11 +2220,11 @@ namespace System.Windows.Forms { public void AutoResizeRows (DataGridViewAutoSizeRowsMode autoSizeRowsMode) { if (!Enum.IsDefined(typeof(DataGridViewAutoSizeRowsMode), autoSizeRowsMode)) - throw new InvalidEnumArgumentException ("Parameter AutoSizeRowsMode is not valid DataGridViewRowsMode."); + throw new InvalidEnumArgumentException ("Parameter autoSizeRowsMode is not a valid DataGridViewRowsMode."); if ((autoSizeRowsMode == DataGridViewAutoSizeRowsMode.AllHeaders || autoSizeRowsMode == DataGridViewAutoSizeRowsMode.DisplayedHeaders) && rowHeadersVisible == false) - throw new InvalidOperationException ("Parameter AutoSizeRowsMode cant be AllHeaders or DisplayedHeaders in this DataGridView."); + throw new InvalidOperationException ("Parameter autoSizeRowsMode cannot be AllHeaders or DisplayedHeaders in this DataGridView."); if (autoSizeRowsMode == DataGridViewAutoSizeRowsMode.None) - throw new ArgumentException ("Parameter AutoSieRowsMode cant be None."); + throw new ArgumentException ("Parameter autoSizeRowsMode cannot be None."); AutoResizeRows (autoSizeRowsMode, false); } @@ -2150,7 +2232,7 @@ namespace System.Windows.Forms { public virtual bool BeginEdit (bool selectAll) { if (currentCell == null || currentCell.IsInEditMode) return false; - + if (currentCell.RowIndex >= 0) { if ((currentCell.InheritedState & DataGridViewElementStates.ReadOnly) == DataGridViewElementStates.ReadOnly) { return false; @@ -2159,7 +2241,8 @@ namespace System.Windows.Forms { DataGridViewCell cell = currentCell; Type editType = cell.EditType; - if (editType == null) + + if (editType == null && !(cell is IDataGridViewEditingCell)) return false; // Give user a chance to cancel the edit @@ -2168,27 +2251,54 @@ namespace System.Windows.Forms { if (e.Cancel) return false; - - cell.SetIsInEditMode (true); - Control ctrl = EditingControlInternal; - bool isCorrectType = ctrl != null && ctrl.GetType () == editType; - if (ctrl != null && !isCorrectType) { - ctrl = null; + + // If the user begins an edit in the NewRow, add a new row + if (CurrentCell.RowIndex == NewRowIndex) { + new_row_commited = false; + OnUserAddedRow (new DataGridViewRowEventArgs (Rows[NewRowIndex])); } - if (ctrl == null) { - ctrl = (Control) Activator.CreateInstance (editType); - EditingControlInternal = ctrl; + + cell.SetIsInEditMode (true); + + // The cell has an editing control we need to setup + if (editType != null) { + Control ctrl = EditingControlInternal; + + // Check if we can reuse the one we already have + bool isCorrectType = ctrl != null && ctrl.GetType () == editType; + + if (!isCorrectType) + ctrl = null; + + // We couldn't use the existing one, create a new one + if (ctrl == null) { + ctrl = (Control) Activator.CreateInstance (editType); + EditingControlInternal = ctrl; + } + + // Call some functions that allows the editing control to get setup + DataGridViewCellStyle style = cell.RowIndex == -1 ? DefaultCellStyle : cell.InheritedStyle; + + cell.InitializeEditingControl (cell.RowIndex, cell.FormattedValue, style); + cell.PositionEditingControl (true, true, this.GetCellDisplayRectangle (cell.ColumnIndex, cell.RowIndex, false), bounds, style, false, false, (columns [cell.ColumnIndex].DisplayIndex == 0), (cell.RowIndex == 0)); + + // Show the editing control + EditingControlInternal.Visible = true; + + IDataGridViewEditingControl dgvEditingControl = (IDataGridViewEditingControl) EditingControlInternal; + if (dgvEditingControl != null) { + dgvEditingControl.EditingControlDataGridView = this; + dgvEditingControl.EditingControlRowIndex = currentCell.OwningRow.Index; + dgvEditingControl.ApplyCellStyleToEditingControl (style); + dgvEditingControl.PrepareEditingControlForEdit (selectAll); + dgvEditingControl.EditingControlFormattedValue = currentCell.EditedFormattedValue; + } + return true; } - IDataGridViewEditingControl edControl = ctrl as IDataGridViewEditingControl; - DataGridViewCellStyle style = cell.RowIndex == -1 ? DefaultCellStyle : cell.InheritedStyle; - cell.InitializeEditingControl (cell.RowIndex, cell.FormattedValue, style); - - cell.PositionEditingControl (true, true, this.GetCellDisplayRectangle (cell.ColumnIndex, cell.RowIndex, false), bounds, style, false, false, (columns [cell.ColumnIndex].DisplayIndex == 0), (cell.RowIndex == 0)); - EditingControlInternal.Visible = true; - - if (edControl != null) - (EditingControlInternal as IDataGridViewEditingControl).PrepareEditingControlForEdit (selectAll); + // If we are here, it means we have a cell that does not have an editing control + // and simply implements IDataGridViewEditingCell itself. + (cell as IDataGridViewEditingCell).PrepareEditingCellForEdit (selectAll); return true; } @@ -2196,6 +2306,17 @@ namespace System.Windows.Forms { public bool CancelEdit () { if (currentCell != null && currentCell.IsInEditMode) { + // The user's typing caused a new row to be created, but + // now they are canceling that typing, we have to remove + // the new row we added. + if (!new_row_commited) { + DataGridViewRow delete_row = EditingRow; + Rows.RemoveInternal (delete_row); + editing_row = Rows[currentCell.RowIndex]; + OnUserDeletedRow (new DataGridViewRowEventArgs (delete_row)); + new_row_commited = true; + } + currentCell.SetIsInEditMode (false); currentCell.DetachEditingControl (); OnCellEndEdit (new DataGridViewCellEventArgs (currentCell.ColumnIndex, currentCell.RowIndex)); @@ -2216,14 +2337,29 @@ namespace System.Windows.Forms { public bool CommitEdit (DataGridViewDataErrorContexts context) { - if (currentCell != null && currentCell.IsInEditMode) { - IDataGridViewEditingControl ctrl = EditingControl as IDataGridViewEditingControl; - ctrl.GetEditingControlFormattedValue (DataGridViewDataErrorContexts.Commit); - currentCell.Value = ctrl.GetEditingControlFormattedValue (DataGridViewDataErrorContexts.Commit); - return true; + if (currentCell != null && currentCell.OwningRow.DataBoundItem != null) { + Object ob = currentCell.OwningRow.DataBoundItem; + PropertyDescriptor property = TypeDescriptor.GetProperties (ob)[currentCell.OwningColumn.DataPropertyName]; + if (property != null && !property.IsReadOnly) { + try { + object value = currentCell.Value; + if (property.Converter != null && + property.Converter.CanConvertFrom (value.GetType())) + value = property.Converter.ConvertFrom (value); + property.SetValue (ob, value); + return true; + } catch (Exception exc) { + DataGridViewDataErrorEventArgs args = new DataGridViewDataErrorEventArgs (exc, currentCell.ColumnIndex, + currentCell.RowIndex, context); + InternalOnDataError (args); + if (args.ThrowException) + throw exc; + return false; + } + } } - - return false; + + return true; } [MonoTODO ("Always includes partial columns")] @@ -2240,39 +2376,59 @@ namespace System.Windows.Forms { return result; } - [MonoTODO ("Always includes partial rows")] public int DisplayedRowCount (bool includePartialRow) { int result = 0; - - for (int i = first_row_index; i < Rows.Count; i++) - if (Rows[i].Displayed) + int rowTop = 0; + + if (ColumnHeadersVisible) + rowTop += ColumnHeadersHeight; + + for (int index = first_row_index; index < Rows.Count; index++) { + DataGridViewRow row = GetRowInternal (index); + if (rowTop + row.Height < ClientSize.Height) { result++; - else + rowTop += row.Height; + } else { + if (includePartialRow) + result++; break; + } + } return result; } public bool EndEdit () { - if (currentCell != null && currentCell.IsInEditMode) { - IDataGridViewEditingControl ctrl = EditingControl as IDataGridViewEditingControl; - ctrl.GetEditingControlFormattedValue (DataGridViewDataErrorContexts.Commit); - currentCell.Value = ctrl.GetEditingControlFormattedValue (DataGridViewDataErrorContexts.Commit); - - currentCell.SetIsInEditMode (false); - currentCell.DetachEditingControl (); - OnCellEndEdit (new DataGridViewCellEventArgs (currentCell.ColumnIndex, currentCell.RowIndex)); - } - - return true; + return EndEdit (DataGridViewDataErrorContexts.Commit); } [MonoTODO ("Does not use context parameter")] public bool EndEdit (DataGridViewDataErrorContexts context) { - return EndEdit (); + if (currentCell == null || !currentCell.IsInEditMode) + return true; + + if (EditingControl != null) { + IDataGridViewEditingControl ctrl = EditingControl as IDataGridViewEditingControl; + currentCell.Value = ctrl.GetEditingControlFormattedValue (DataGridViewDataErrorContexts.Commit); + if (!CommitEdit (context)) { + EditingControl.Focus (); + return false; + } + currentCell.DetachEditingControl (); + } else if (currentCell is IDataGridViewEditingCell) { + currentCell.Value = (currentCell as IDataGridViewEditingCell).EditingCellFormattedValue; + if (!CommitEdit (context)) + return false; + } + + currentCell.SetIsInEditMode (false); + new_row_commited = true; + OnCellEndEdit (new DataGridViewCellEventArgs (currentCell.ColumnIndex, currentCell.RowIndex)); + Focus (); + return true; } public int GetCellCount (DataGridViewElementStates includeFilter) { @@ -2710,7 +2866,8 @@ namespace System.Windows.Forms { } public virtual void NotifyCurrentCellDirty (bool dirty) { - throw new NotImplementedException(); + if (currentCell != null) + InvalidateCell (currentCell); } public bool RefreshEdit () @@ -2783,26 +2940,46 @@ namespace System.Windows.Forms { throw new ArgumentNullException ("dataGridViewColumn"); if (dataGridViewColumn.DataGridView != this) throw new ArgumentException ("dataGridViewColumn"); - if (DataSource != null && !dataGridViewColumn.IsDataBound) - throw new ArgumentException ("dataGridViewColumn"); - if (VirtualMode && !dataGridViewColumn.IsDataBound) - throw new InvalidOperationException (); + + if (!EndEdit ()) + return; if (SortedColumn != null) SortedColumn.HeaderCell.SortGlyphDirection = SortOrder.None; - EndEdit (); - - ColumnSorter sorter = new ColumnSorter (dataGridViewColumn, direction); - Rows.Sort (sorter); - sortedColumn = dataGridViewColumn; - sortOrder = (SortOrder)direction + 1; + sortOrder = direction == ListSortDirection.Ascending ? SortOrder.Ascending : SortOrder.Descending; + + if (Rows.Count == 0) + return; - dataGridViewColumn.HeaderCell.SortGlyphDirection = (SortOrder)direction + 1; + IBindingList bindingList = DataSource as IBindingList; + if (dataGridViewColumn.IsDataBound) { + if (bindingList != null && bindingList.SupportsSorting) { + CurrencyManager currencyManager = (CurrencyManager) this.BindingContext[DataSource]; + bindingList.ApplySort (currencyManager.GetItemProperties()[dataGridViewColumn.DataPropertyName], direction); + dataGridViewColumn.HeaderCell.SortGlyphDirection = sortOrder; + } + } else { + // Figure out if this is a numeric sort or text sort + bool is_numeric = true; + double n; + + foreach (DataGridViewRow row in Rows) { + object val = row.Cells[dataGridViewColumn.Index].Value; + + if (val != null && !double.TryParse (val.ToString (), out n)) { + is_numeric = false; + break; + } + } + + ColumnSorter sorter = new ColumnSorter (dataGridViewColumn, direction, is_numeric); + Rows.Sort (sorter); + dataGridViewColumn.HeaderCell.SortGlyphDirection = sortOrder; + } Invalidate (); - OnSorted (EventArgs.Empty); } @@ -2904,7 +3081,17 @@ namespace System.Windows.Forms { [MonoTODO ("Does not use fixedWidth parameter")] protected void AutoResizeRow (int rowIndex, DataGridViewAutoSizeRowMode autoSizeRowMode, bool fixedWidth) { - AutoResizeRow (rowIndex, autoSizeRowMode); + if (autoSizeRowMode == DataGridViewAutoSizeRowMode.RowHeader && !rowHeadersVisible) + throw new InvalidOperationException ("row headers are not visible"); + if (rowIndex < 0 || rowIndex > Rows.Count - 1) + throw new ArgumentOutOfRangeException ("rowIndex"); + + DataGridViewRow row = GetRowInternal (rowIndex); + + int new_height = row.GetPreferredHeight (rowIndex, autoSizeRowMode, true); + + if (row.Height != new_height) + row.SetAutoSizeHeight (new_height); } [MonoTODO ("Does not use fixedColumnHeadersHeight or fixedRowsHeight parameter")] @@ -2919,58 +3106,46 @@ namespace System.Windows.Forms { AutoResizeRowHeadersWidth (rowHeadersWidthSizeMode); } - [MonoTODO ("Does not use fixedMode parameter")] + [MonoTODO ("Does not use fixedWidth parameter")] protected void AutoResizeRows (DataGridViewAutoSizeRowsMode autoSizeRowsMode, bool fixedWidth) { if (autoSizeRowsMode == DataGridViewAutoSizeRowsMode.None) return; - bool include_headers = false; - bool include_cells = false; bool displayed_only = false; - + DataGridViewAutoSizeRowMode mode = DataGridViewAutoSizeRowMode.AllCells; + switch (autoSizeRowsMode) { case DataGridViewAutoSizeRowsMode.AllHeaders: - include_headers = true; + mode = DataGridViewAutoSizeRowMode.RowHeader; break; case DataGridViewAutoSizeRowsMode.AllCellsExceptHeaders: - include_cells = true; + mode = DataGridViewAutoSizeRowMode.AllCellsExceptHeader; break; case DataGridViewAutoSizeRowsMode.AllCells: - include_cells = true; - include_headers = true; + mode = DataGridViewAutoSizeRowMode.AllCells; break; case DataGridViewAutoSizeRowsMode.DisplayedHeaders: - include_headers = true; + mode = DataGridViewAutoSizeRowMode.RowHeader; displayed_only = true; break; case DataGridViewAutoSizeRowsMode.DisplayedCellsExceptHeaders: - include_cells = true; + mode = DataGridViewAutoSizeRowMode.AllCellsExceptHeader; displayed_only = true; break; case DataGridViewAutoSizeRowsMode.DisplayedCells: - include_cells = true; - include_headers = true; + mode = DataGridViewAutoSizeRowMode.AllCells; displayed_only = true; break; } foreach (DataGridViewRow row in Rows) { - int new_height = 0; - - if (include_headers) - if (!displayed_only || row.HeaderCell.Displayed) - new_height = Math.Max (new_height, row.HeaderCell.PreferredSize.Height); - - if (include_cells) - foreach (DataGridViewCell cell in row.Cells) - if (!displayed_only || cell.Displayed) - new_height = Math.Max (new_height, cell.PreferredSize.Height); - - new_height = Math.Max (new_height, row.MinimumHeight); - - if (row.Height != new_height) - row.Height = new_height; + if (!displayed_only || row.Displayed) { + int new_height = row.GetPreferredHeight (row.Index, mode, fixedWidth); + + if (row.Height != new_height) + row.SetAutoSizeHeight (new_height); + } } } @@ -3145,7 +3320,7 @@ namespace System.Windows.Forms { eh (this, e); } - protected virtual void OnAutoSizeColumnModeChanged (DataGridViewAutoSizeColumnModeEventArgs e) + protected internal virtual void OnAutoSizeColumnModeChanged (DataGridViewAutoSizeColumnModeEventArgs e) { DataGridViewAutoSizeColumnModeEventHandler eh = (DataGridViewAutoSizeColumnModeEventHandler)(Events [AutoSizeColumnModeChangedEvent]); if (eh != null) @@ -3406,6 +3581,10 @@ namespace System.Windows.Forms { eh (this, e); } + internal void OnCellStateChangedInternal (DataGridViewCellStateChangedEventArgs e) { + this.OnCellStateChanged (e); + } + protected virtual void OnCellStateChanged (DataGridViewCellStateChangedEventArgs e) { DataGridViewCellStateChangedEventHandler eh = (DataGridViewCellStateChangedEventHandler)(Events [CellStateChangedEvent]); @@ -3460,7 +3639,7 @@ namespace System.Windows.Forms { eh (this, e); } - protected virtual void OnCellValueNeeded (DataGridViewCellValueEventArgs e) + protected internal virtual void OnCellValueNeeded (DataGridViewCellValueEventArgs e) { DataGridViewCellValueEventHandler eh = (DataGridViewCellValueEventHandler)(Events [CellValueNeededEvent]); if (eh != null) @@ -3476,11 +3655,11 @@ namespace System.Windows.Forms { internal void OnColumnAddedInternal (DataGridViewColumnEventArgs e) { - RowTemplate.Cells.Add ((DataGridViewCell)e.Column.CellTemplate.Clone ()); - - foreach (DataGridViewRow row in Rows) - row.Cells.Add ((DataGridViewCell)RowTemplate.Cells[RowTemplate.Cells.Count - 1].Clone ()); - + if (e.Column.CellTemplate != null) { + foreach (DataGridViewRow row in Rows) + row.Cells.Add ((DataGridViewCell)e.Column.CellTemplate.Clone ()); + } + AutoResizeColumnsInternal (); OnColumnAdded (e); PrepareEditingRow (false, true); @@ -3613,6 +3792,20 @@ namespace System.Windows.Forms { eh (this, e); } + internal void OnColumnRemovedInternal (DataGridViewColumnEventArgs e) + { + if (e.Column.CellTemplate != null) { + int index = e.Column.Index; + + foreach (DataGridViewRow row in Rows) + row.Cells.RemoveAt (index); + } + + AutoResizeColumnsInternal (); + OnColumnRemoved (e); + PrepareEditingRow (false, true); + } + protected virtual void OnColumnRemoved (DataGridViewColumnEventArgs e) { DataGridViewColumnEventHandler eh = (DataGridViewColumnEventHandler)(Events [ColumnRemovedEvent]); @@ -3764,7 +3957,7 @@ namespace System.Windows.Forms { { base.OnHandleCreated(e); - if (Rows.Count > 0 && Columns.Count > 0) + if (CurrentCell == null && Rows.Count > 0 && Columns.Count > 0) MoveCurrentCell (ColumnDisplayIndexToIndex (0), 0, true, false, false, false); } @@ -3802,7 +3995,8 @@ namespace System.Windows.Forms { horizontalScrollBar.Bounds = new Rectangle (BorderWidth, Height - BorderWidth - horizontalScrollBar.Height, Width - (2 * BorderWidth), horizontalScrollBar.Height); else if (verticalScrollBar.Visible) verticalScrollBar.Bounds = new Rectangle (Width - BorderWidth - verticalScrollBar.Width, BorderWidth, verticalScrollBar.Width, Height - (2 * BorderWidth)); - + + AutoResizeColumnsInternal (); Invalidate (); } @@ -3823,6 +4017,10 @@ namespace System.Windows.Forms { protected override void OnMouseClick (MouseEventArgs e) { base.OnMouseClick(e); + + if (column_resize_active || row_resize_active) + return; + //Console.WriteLine("Mouse: Clicks: {0}; Delta: {1}; X: {2}; Y: {3};", e.Clicks, e.Delta, e.X, e.Y); HitTestInfo hit = HitTest (e.X, e.Y); @@ -3835,8 +4033,10 @@ namespace System.Windows.Forms { DataGridViewCell cell = GetCellInternal (hit.ColumnIndex, hit.RowIndex); - if (cell.GetContentBounds (hit.RowIndex).Contains (cellpoint)) - cell.OnContentClickInternal (new DataGridViewCellEventArgs (hit.ColumnIndex, hit.RowIndex)); + if (cell.GetContentBounds (hit.RowIndex).Contains (cellpoint)) { + DataGridViewCellEventArgs dgvcea = new DataGridViewCellEventArgs (hit.ColumnIndex, hit.RowIndex); + OnCellContentClick (dgvcea); + } break; case DataGridViewHitTestType.ColumnHeader: @@ -3996,45 +4196,76 @@ namespace System.Windows.Forms { { base.OnMouseDown(e); + if (!EndEdit ()) + return; + HitTestInfo hitTest = HitTest(e.X, e.Y); DataGridViewCell cell = null; DataGridViewRow row = null; Rectangle cellBounds; + if (hitTest.Type == DataGridViewHitTestType.ColumnHeader && MouseOverColumnResize (hitTest.ColumnIndex, e.X)) { + if (e.Clicks == 2) { + AutoResizeColumn (hitTest.ColumnIndex); + return; + } + + resize_band = hitTest.ColumnIndex; + column_resize_active = true; + resize_band_start = e.X; + resize_band_delta = 0; + DrawVerticalResizeLine (resize_band_start); + return; + } + + if (hitTest.Type == DataGridViewHitTestType.RowHeader && MouseOverRowResize (hitTest.RowIndex, e.Y)) { + if (e.Clicks == 2) { + AutoResizeRow (hitTest.RowIndex); + return; + } + + resize_band = hitTest.RowIndex; + row_resize_active = true; + resize_band_start = e.Y; + resize_band_delta = 0; + DrawHorizontalResizeLine (resize_band_start); + return; + } + if (hitTest.Type == DataGridViewHitTestType.Cell) { + row = rows [hitTest.RowIndex]; + cell = row.Cells [hitTest.ColumnIndex]; + SetCurrentCellAddressCore (cell.ColumnIndex, cell.RowIndex, false, true, true); cellBounds = GetCellDisplayRectangle (hitTest.ColumnIndex, hitTest.RowIndex, false); OnCellMouseDown (new DataGridViewCellMouseEventArgs (hitTest.ColumnIndex, hitTest.RowIndex, e.X - cellBounds.X, e.Y - cellBounds.Y, e)); OnCellClick (new DataGridViewCellEventArgs (hitTest.ColumnIndex, hitTest.RowIndex)); - row = rows [hitTest.RowIndex]; - cell = row.Cells [hitTest.ColumnIndex]; } DoSelectionOnMouseDown (hitTest); if (hitTest.Type != DataGridViewHitTestType.Cell) { + if (hitTest.Type == DataGridViewHitTestType.ColumnHeader) + pressed_header_cell = columns [hitTest.ColumnIndex].HeaderCell; + else if (hitTest.Type == DataGridViewHitTestType.RowHeader) + pressed_header_cell = rows [hitTest.RowIndex].HeaderCell; Invalidate (); return; } - if (cell == currentCell) { - BeginEdit (true); - } else if (currentCell != null) { - EndEdit (); - OnCellLeave(new DataGridViewCellEventArgs(currentCell.ColumnIndex, currentCell.RowIndex)); - } - currentCell = cell; - currentCellAddress = new Point (currentCell.ColumnIndex, currentCell.RowIndex); - currentRow = cell.OwningRow; - OnCurrentCellChanged(EventArgs.Empty); - OnCellEnter(new DataGridViewCellEventArgs(cell.ColumnIndex, cell.RowIndex)); - if (editMode == DataGridViewEditMode.EditOnEnter) { - BeginEdit (true); - } Invalidate(); return; } + private void UpdateBindingPosition (int position) + { + if (DataSource != null && BindingContext != null) { + CurrencyManager currencyManager = this.BindingContext[DataSource] as CurrencyManager; + if (currencyManager != null) + currencyManager.Position = position; + } + } + protected override void OnMouseEnter (EventArgs e) { base.OnMouseEnter(e); @@ -4048,15 +4279,42 @@ namespace System.Windows.Forms { OnCellMouseLeave (new DataGridViewCellEventArgs (hover_cell.ColumnIndex, hover_cell.RowIndex)); hover_cell = null; } + + EnteredHeaderCell = null; } protected override void OnMouseMove (MouseEventArgs e) { base.OnMouseMove (e); - + + if (column_resize_active) { + // Erase the old line + DrawVerticalResizeLine (resize_band_start + resize_band_delta); + + resize_band_delta = e.X - resize_band_start; + + // Draw the new line + DrawVerticalResizeLine (resize_band_start + resize_band_delta); + return; + } + + if (row_resize_active) { + // Erase the old line + DrawHorizontalResizeLine (resize_band_start + resize_band_delta); + + resize_band_delta = e.Y - resize_band_start; + + // Draw the new line + DrawHorizontalResizeLine (resize_band_start + resize_band_delta); + return; + } + + Cursor new_cursor = Cursors.Default; HitTestInfo hit = this.HitTest (e.X, e.Y); if (hit.Type == DataGridViewHitTestType.Cell) { + EnteredHeaderCell = null; + DataGridViewCell new_cell = GetCellInternal (hit.ColumnIndex, hit.RowIndex); // Check if we have moved into an error icon area @@ -4108,6 +4366,11 @@ namespace System.Windows.Forms { } else if (hit.Type == DataGridViewHitTestType.RowHeader) { DataGridViewRowHeaderCell new_cell = Rows[hit.RowIndex].HeaderCell; + EnteredHeaderCell = new_cell; + + if (MouseOverRowResize (hit.RowIndex, e.Y)) + new_cursor = Cursors.HSplit; + // Check if we have moved into an error icon area Rectangle icon = new_cell.InternalErrorIconsBounds; @@ -4124,6 +4387,8 @@ namespace System.Windows.Forms { MouseLeftErrorIcon (new_cell); } } else if (hit.Type == DataGridViewHitTestType.TopLeftHeader) { + EnteredHeaderCell = null; + DataGridViewTopLeftHeaderCell new_cell = (DataGridViewTopLeftHeaderCell)TopLeftHeaderCell; // Check if we have moved into an error icon area @@ -4143,24 +4408,63 @@ namespace System.Windows.Forms { } } else { + if (hit.Type == DataGridViewHitTestType.ColumnHeader) { + EnteredHeaderCell = Columns [hit.ColumnIndex].HeaderCell; + + if (MouseOverColumnResize (hit.ColumnIndex, e.X)) + new_cursor = Cursors.VSplit; + } else + EnteredHeaderCell = null; + // We have left the cell area if (hover_cell != null) { OnCellMouseLeave (new DataGridViewCellEventArgs (hover_cell.ColumnIndex, hover_cell.RowIndex)); hover_cell = null; } } + + Cursor = new_cursor; } protected override void OnMouseUp (MouseEventArgs e) { base.OnMouseUp(e); + if (column_resize_active) { + column_resize_active = false; + + if (resize_band_delta + Columns[resize_band].Width < 0) + resize_band_delta = -Columns[resize_band].Width; + + Columns[resize_band].Width = Math.Max (resize_band_delta + Columns[resize_band].Width, Columns[resize_band].MinimumWidth); + Invalidate (); + return; + } + + if (row_resize_active) { + row_resize_active = false; + + if (resize_band_delta + Rows[resize_band].Height < 0) + resize_band_delta = -Rows[resize_band].Height; + + Rows[resize_band].Height = Math.Max (resize_band_delta + Rows[resize_band].Height, Rows[resize_band].MinimumHeight); + Invalidate (); + return; + } + HitTestInfo hit = this.HitTest (e.X, e.Y); if (hit.Type == DataGridViewHitTestType.Cell) { Rectangle display = GetCellDisplayRectangle (hit.ColumnIndex, hit.RowIndex, false); OnCellMouseUp (new DataGridViewCellMouseEventArgs (hit.ColumnIndex, hit.RowIndex, e.X - display.X, e.Y - display.Y, e)); } + + if (pressed_header_cell != null) { + DataGridViewHeaderCell cell = pressed_header_cell; + pressed_header_cell = null; + if (ThemeEngine.Current.DataGridViewHeaderCellHasPressedStyle (this)) + Invalidate (GetHeaderCellBounds (cell)); + } } protected override void OnMouseWheel (MouseEventArgs e) @@ -4198,7 +4502,7 @@ namespace System.Windows.Forms { bounds.Inflate (-BorderWidth, -BorderWidth); // Paint the top left cell - if (rowHeadersVisible && columnHeadersVisible) { + if (rowHeadersVisible && columnHeadersVisible && ColumnCount > 0) { Rectangle topleftbounds = new Rectangle (bounds.X, bounds.Y, rowHeadersWidth, columnHeadersHeight); TopLeftHeaderCell.PaintWork (g, e.ClipRectangle, topleftbounds, -1, TopLeftHeaderCell.State, ColumnHeadersDefaultCellStyle, AdvancedColumnHeadersBorderStyle, DataGridViewPaintParts.All); @@ -4224,7 +4528,7 @@ namespace System.Windows.Forms { DataGridViewAdvancedBorderStyle intermediateBorderStyle = (DataGridViewAdvancedBorderStyle)((ICloneable)this.AdvancedColumnHeadersBorderStyle).Clone (); DataGridViewAdvancedBorderStyle borderStyle = AdjustColumnHeaderBorderStyle (this.AdvancedColumnHeadersBorderStyle, intermediateBorderStyle, cell.ColumnIndex == 0, cell.ColumnIndex == columns.Count - 1); - cell.PaintWork (g, e.ClipRectangle, headerBounds, -1, cell.State, columnHeadersDefaultCellStyle, borderStyle, DataGridViewPaintParts.All); + cell.PaintWork (g, e.ClipRectangle, headerBounds, -1, cell.State, cell.InheritedStyle, borderStyle, DataGridViewPaintParts.All); headerBounds.X += col.Width; } @@ -4235,9 +4539,8 @@ namespace System.Windows.Forms { gridWidth = rowHeadersVisible ? rowHeadersWidth : 0; gridHeight = 0; - int rows_displayed = 0; int first_row_height = Rows.Count > 0 ? Rows[Math.Min (Rows.Count - 1, first_row_index)].Height : 0; - int room_left = this.Height; +// int room_left = this.Height; // Reset all columns to !Displayed for (int i = 0; i < Columns.Count; i++) @@ -4275,9 +4578,7 @@ namespace System.Windows.Forms { bounds.Y += bounds.Height; bounds.X = BorderWidth; - if (bounds.Y < ClientSize.Height - (horizontalScrollBar.Visible ? horizontalScrollBar.Height : 0)) - rows_displayed++; - else + if (bounds.Y >= ClientSize.Height - (horizontalScrollBar.Visible ? horizontalScrollBar.Height : 0)) break; gridHeight += row.Height; @@ -4530,7 +4831,21 @@ namespace System.Windows.Forms { if (eh != null) eh (this, e); } - protected internal virtual void OnRowsRemoved (DataGridViewRowsRemovedEventArgs e) + internal void OnRowsRemovedInternal (DataGridViewRowsRemovedEventArgs e) + { + if (selected_rows != null) + selected_rows.InternalClear (); + if (selected_columns != null) + selected_columns.InternalClear (); + + if (Rows.Count > 0 && Columns.Count > 0 && currentCell != null && + currentCell.RowIndex >= e.RowIndex) + MoveCurrentCell (0, Math.Min (e.RowIndex, Rows.Count - 2), true, false, false, true); + Invalidate (); + OnRowsRemoved (e); + } + + protected virtual void OnRowsRemoved (DataGridViewRowsRemovedEventArgs e) { DataGridViewRowsRemovedEventHandler eh = (DataGridViewRowsRemovedEventHandler)(Events [RowsRemovedEvent]); if (eh != null) eh (this, e); @@ -4585,6 +4900,11 @@ namespace System.Windows.Forms { protected virtual void OnUserAddedRow (DataGridViewRowEventArgs e) { + editing_row = null; + PrepareEditingRow (false, false); + + e = new DataGridViewRowEventArgs (editing_row); + DataGridViewRowEventHandler eh = (DataGridViewRowEventHandler)(Events [UserAddedRowEvent]); if (eh != null) eh (this, e); } @@ -4660,9 +4980,6 @@ namespace System.Windows.Forms { case Keys.Space: return ProcessSpaceKey (e.KeyData); case Keys.Tab: - case Keys.Shift | Keys.Tab: - case Keys.Control | Keys.Tab: - case Keys.Control | Keys.Shift | Keys.Tab: return ProcessTabKey (e.KeyData); case Keys.Up: return ProcessUpKey (e.KeyData); @@ -4674,10 +4991,29 @@ namespace System.Windows.Forms { return false; } - [MonoTODO ("What does delete do?")] protected bool ProcessDeleteKey (Keys keyData) { - return false; + if (!allowUserToDeleteRows || SelectedRows.Count == 0) + return false; + + int index = Math.Max (selected_row - SelectedRows.Count + 1, 0); + + for (int i = SelectedRows.Count - 1; i >= 0; i--) { + DataGridViewRow row = SelectedRows[i]; + + if (row.IsNewRow) + continue; + + if (hover_cell != null && hover_cell.OwningRow == row) + hover_cell = null; + + if (DataSource != null && DataSource is DataSet) + (DataSource as DataSet).Tables[dataMember].Rows.RemoveAt (row.Index); + else + Rows.RemoveAt (row.Index); + } + + return true; } protected override bool ProcessDialogKey (Keys keyData) @@ -4700,6 +5036,12 @@ namespace System.Windows.Forms { if (ProcessDataGridViewKey (new KeyEventArgs (keyData))) return true; + break; + case Keys.Enter: + case Keys.Escape: + if (ProcessDataGridViewKey (new KeyEventArgs (keyData))) + return true; + break; } @@ -4711,8 +5053,6 @@ namespace System.Windows.Forms { int current_row = CurrentCellAddress.Y; if (current_row < Rows.Count - 1) { - EndEdit (); - // Move to the last cell in the column if ((keyData & Keys.Control) == Keys.Control) MoveCurrentCell (CurrentCellAddress.X, Rows.Count - 1, true, (keyData & Keys.Control) == Keys.Control, (keyData & Keys.Shift) == Keys.Shift, true); @@ -4747,19 +5087,12 @@ namespace System.Windows.Forms { protected bool ProcessEnterKey (Keys keyData) { - if (!IsCurrentCellInEditMode) - return false; - - CommitEdit (DataGridViewDataErrorContexts.Commit); - - // Move one cell down - if ((keyData & Keys.Control) == 0) { - int current_row = CurrentCellAddress.Y; - - if (current_row < Rows.Count - 1) - MoveCurrentCell (CurrentCellAddress.X, current_row + 1, true, (keyData & Keys.Control) == Keys.Control, (keyData & Keys.Shift) == Keys.Shift, true); - } + if (ProcessDownKey (keyData)) + return true; + // ProcessDown may fail if we are on the last row, + // but Enter should still EndEdit if this is the last row + EndEdit (); return true; } @@ -4850,8 +5183,6 @@ namespace System.Windows.Forms { int disp_index = ColumnIndexToDisplayIndex (currentCellAddress.X); if (disp_index > 0) { - EndEdit (); - // Move to the first cell in the row if ((keyData & Keys.Control) == Keys.Control) MoveCurrentCell (ColumnDisplayIndexToIndex (0), currentCellAddress.Y, true, (keyData & Keys.Control) == Keys.Control, (keyData & Keys.Shift) == Keys.Shift, true); @@ -4871,8 +5202,6 @@ namespace System.Windows.Forms { int current_row = CurrentCellAddress.Y; if (current_row < Rows.Count - 1) { - EndEdit (); - // Move one "page" of cells down int new_row = Math.Min (Rows.Count - 1, current_row + DisplayedRowCount (false)); @@ -4890,8 +5219,6 @@ namespace System.Windows.Forms { int current_row = CurrentCellAddress.Y; if (current_row > 0) { - EndEdit (); - // Move one "page" of cells up int new_row = Math.Max (0, current_row - DisplayedRowCount (false)); @@ -4908,8 +5235,6 @@ namespace System.Windows.Forms { int disp_index = ColumnIndexToDisplayIndex (currentCellAddress.X); if (disp_index < Columns.Count - 1) { - EndEdit (); - // Move to the last cell in the row if ((keyData & Keys.Control) == Keys.Control) MoveCurrentCell (ColumnDisplayIndexToIndex (Columns.Count - 1), currentCellAddress.Y, true, (keyData & Keys.Control) == Keys.Control, (keyData & Keys.Shift) == Keys.Shift, true); @@ -4957,8 +5282,6 @@ namespace System.Windows.Forms { protected bool ProcessTabKey (Keys keyData) { - EndEdit (); - Form f = FindForm (); if (f != null) @@ -5002,8 +5325,6 @@ namespace System.Windows.Forms { int current_row = CurrentCellAddress.Y; if (current_row > 0) { - EndEdit (); - // Move to the first cell in the column if ((keyData & Keys.Control) == Keys.Control) MoveCurrentCell (CurrentCellAddress.X, 0, true, (keyData & Keys.Control) == Keys.Control, (keyData & Keys.Shift) == Keys.Shift, true); @@ -5032,7 +5353,7 @@ namespace System.Windows.Forms { base.SetBoundsCore(x, y, width, height, specified); } - [MonoTODO ("Does not use validateCurrentCell or throughMouseClick")] + [MonoTODO ("Does not use validateCurrentCell")] protected virtual bool SetCurrentCellAddressCore (int columnIndex, int rowIndex, bool setAnchorCellAddress, bool validateCurrentCell, bool throughMouseClick) { if ((columnIndex < 0 || columnIndex > Columns.Count - 1) && rowIndex != -1) @@ -5050,14 +5371,30 @@ namespace System.Windows.Forms { if (cell != null && !cell.Visible) throw new InvalidOperationException ("cell is not visible"); - if (setAnchorCellAddress) - anchor_cell = new Point (columnIndex, rowIndex); + if (cell != currentCell) { + if (currentCell != null) { + if (currentCell.IsInEditMode && !EndEdit ()) + return false; + OnCellLeave (new DataGridViewCellEventArgs(currentCell.ColumnIndex, currentCell.RowIndex)); + OnRowLeave (new DataGridViewCellEventArgs (currentCell.ColumnIndex, currentCell.RowIndex)); + } + + currentCell = cell; + if (setAnchorCellAddress) + anchor_cell = new Point (columnIndex, rowIndex); + currentCellAddress = new Point (columnIndex, rowIndex); + + UpdateBindingPosition (currentCell.RowIndex); + OnRowEnter (new DataGridViewCellEventArgs (cell.ColumnIndex, cell.RowIndex)); + OnCellEnter (new DataGridViewCellEventArgs(cell.ColumnIndex, cell.RowIndex)); + OnCurrentCellChanged (EventArgs.Empty); + if (throughMouseClick || editMode == DataGridViewEditMode.EditOnEnter) + BeginEdit (true); + } else { + if (throughMouseClick) + BeginEdit (true); + } - currentCellAddress = new Point (columnIndex, rowIndex); - CurrentCell = cell; - - OnCurrentCellChanged (EventArgs.Empty); - return true; } @@ -5087,6 +5424,8 @@ namespace System.Windows.Forms { } else if (selected && !selected_columns.Contains (col)) { selected_columns.InternalAdd (col); } + + Invalidate(); } internal void SetSelectedRowCoreInternal (int rowIndex, bool selected) { @@ -5106,6 +5445,8 @@ namespace System.Windows.Forms { } else if (selected && !selected_rows.Contains (row)) { selected_rows.InternalAdd (row); } + + Invalidate(); } protected override void WndProc (ref Message m) @@ -5131,9 +5472,6 @@ namespace System.Windows.Forms { internal void InternalOnCellValueChanged (DataGridViewCellEventArgs e) { OnCellValueChanged (e); - - if (editing_row != null && e.RowIndex == editing_row.Index) - PrepareEditingRow (true, false); } internal void InternalOnDataError (DataGridViewDataErrorEventArgs e) @@ -5172,12 +5510,14 @@ namespace System.Windows.Forms { internal void OnVScrollBarScroll (object sender, ScrollEventArgs e) { verticalScrollingOffset = e.NewValue; + if (Rows.Count == 0) + return; + int top = 0; for (int index = 0; index < Rows.Count; index++) { DataGridViewRow row = Rows[index]; - - if (e.NewValue <= top + row.Height) { + if (e.NewValue < top + row.Height) { if (first_row_index != index) { first_row_index = index; Invalidate (); @@ -5190,10 +5530,7 @@ namespace System.Windows.Forms { top += row.Height; } - if (Rows.Count == 0) - return; - - first_row_index = Rows.Count - DisplayedRowCount (false) + 1; + first_row_index = Rows.Count - DisplayedRowCount (false); Invalidate (); OnScroll (e); } @@ -5205,10 +5542,10 @@ namespace System.Windows.Forms { internal void OnColumnCollectionChanged (object sender, CollectionChangeEventArgs e) { switch (e.Action) { case CollectionChangeAction.Add: - OnColumnAdded(new DataGridViewColumnEventArgs(e.Element as DataGridViewColumn)); + OnColumnAddedInternal(new DataGridViewColumnEventArgs(e.Element as DataGridViewColumn)); break; case CollectionChangeAction.Remove: - OnColumnRemoved(new DataGridViewColumnEventArgs(e.Element as DataGridViewColumn)); + OnColumnRemovedInternal(new DataGridViewColumnEventArgs(e.Element as DataGridViewColumn)); break; case CollectionChangeAction.Refresh: break; @@ -5229,7 +5566,7 @@ namespace System.Windows.Forms { { float totalFillWeight = 0; int FillCount = 0; // The number of columns that has AutoSizeMode.Fill set - int spaceLeft = ClientSize.Width; + int spaceLeft = ClientSize.Width - (verticalScrollBar.VisibleInternal ? verticalScrollBar.Width : 0); if (RowHeadersVisible) { spaceLeft -= RowHeadersWidth; @@ -5312,7 +5649,8 @@ namespace System.Windows.Forms { case DataGridViewAutoSizeColumnMode.AllCells: case DataGridViewAutoSizeColumnMode.DisplayedCells: case DataGridViewAutoSizeColumnMode.DisplayedCellsExceptHeader: - size = CalculateColumnCellWidth (columnIndex, col.InheritedAutoSizeMode); + size = Math.Max (CalculateColumnCellWidth (columnIndex, col.InheritedAutoSizeMode), + col.HeaderCell.ContentBounds.Width); break; case DataGridViewAutoSizeColumnMode.ColumnHeader: size = col.HeaderCell.ContentBounds.Width; @@ -5349,22 +5687,48 @@ namespace System.Windows.Forms { continue; } - Rectangle cell_rect = GetCellDisplayRectangle (index, i, false); - - result = Math.Max (result, cell_rect.Width); + int cell_width = Rows[i].Cells[index].PreferredSize.Width; + + result = Math.Max (result, cell_width); } return result; } - private void PrepareEditingRow (bool cell_changed, bool column_changed) + Rectangle GetHeaderCellBounds (DataGridViewHeaderCell cell) + { + Rectangle bounds = new Rectangle (ClientRectangle.Location, cell.Size); + if (cell is DataGridViewColumnHeaderCell) { + if (RowHeadersVisible) + bounds.X += RowHeadersWidth; + List sortedColumns = columns.ColumnDisplayIndexSortedArrayList; + for (int index = first_col_index; index < sortedColumns.Count; index++) { + DataGridViewColumn column = sortedColumns [index]; + if (column.Index == cell.ColumnIndex) + break; + bounds.X += column.Width; + } + } else { + if (ColumnHeadersVisible) + bounds.Y += ColumnHeadersHeight; + for (int index = first_row_index; index < Rows.Count; index++) { + DataGridViewRow row = GetRowInternal (index); + if (row.HeaderCell == cell) + break; + bounds.Y += row.Height; + } + } + return bounds; + } + + internal void PrepareEditingRow (bool cell_changed, bool column_changed) { bool show = false; show = ColumnCount > 0 && AllowUserToAddRows; if (!show && editing_row != null) { - Rows.Remove (editing_row); + Rows.RemoveInternal (editing_row); editing_row = null; } else if (show) { if (editing_row != null) { @@ -5373,7 +5737,7 @@ namespace System.Windows.Forms { editing_row = null; } else if (column_changed) { // The number of columns has changed, we need a new editing row. - Rows.Remove (editing_row); + Rows.RemoveInternal (editing_row); editing_row = null; } } @@ -5391,56 +5755,108 @@ namespace System.Windows.Forms { } private void BindIList (IList list) { - // Stuff from a DataSet - if (list is DataView) { - DataView dataView = (DataView) list; - DataTable table = dataView.Table; + if (autoGenerateColumns) { + // Stuff from a DataSet + if (list is DataView) { + DataView dataView = (DataView) list; + DataTable table = dataView.Table; + + foreach (DataColumn dataColumn in table.Columns) { + DataGridViewColumn col = CreateColumnByType (dataColumn.DataType); + + col.Name = dataColumn.ColumnName; + col.DataPropertyName = dataColumn.ColumnName; + col.SetIsDataBound (true); + col.ValueType = dataColumn.DataType; + col.AutoGenerated = true; + + columns.Add (col); + } + } + // Its a generic something or other, like a BindingList, so + // we can figure out the type from the generic type + else if (list.GetType ().GetGenericArguments ().Length > 0) { + GenerateColumnsFromType (list.GetType ().GetGenericArguments ()[0]); + } + // Its a normal array/collection type thing + else if (list.GetType ().IsArray) { + GenerateColumnsFromType (list.GetType ().GetElementType ()); + } else if (list is BindingSource && (list as BindingSource).item_type != null) { + foreach (PropertyDescriptor property in TypeDescriptor.GetProperties ((list as BindingSource).item_type)) { + DataGridViewColumn col = CreateColumnByType (property.PropertyType); + col.Name = property.DisplayName; + col.ReadOnly = property.IsReadOnly; + col.AutoGenerated = true; + columns.Add (col); + } - foreach (DataColumn dataColumn in table.Columns) { - DataGridViewColumn col = CreateColumnByType (dataColumn.DataType); - - col.Name = dataColumn.ColumnName; - col.DataPropertyName = dataColumn.ColumnName; - col.SetIsDataBound (true); - col.ValueType = dataColumn.DataType; - - columns.Add (col); + AllowUserToAddRows = (list as BindingSource).AllowNew; } - - dataView.ListChanged += OnListChanged; } - else if (list.Count > 0) { - DataGridViewCell template = new DataGridViewTextBoxCell(); - foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(list[0])) { - DataGridViewColumn col = new DataGridViewColumn(template); - col.Name = property.DisplayName; - col.ReadOnly = property.IsReadOnly; - columns.Add(col); - } + + // Subscribe to the dataset's change notification + if (list is DataView) { + (list as DataView).ListChanged += OnListChanged; + (list as DataView).Table.ColumnChanged += OnTableColumnChanged; + (list as DataView).Table.TableCleared += OnTableCleared; } - foreach (object element in list) { - DataGridViewRow row = (DataGridViewRow)RowTemplate.Clone (); - rows.InternalAdd (row); - PropertyDescriptorCollection properties = TypeDescriptor.GetProperties (element); + // Add the rows + foreach (object element in list) + AddBoundRow (element); + } + + private void OnBindingSourceDataSourceChanged (object sender, EventArgs args) + { + ClearBinding(); + DoBinding(); + } + + private void AddBoundRow (object element) + { + // Don't add rows if there are no columns + if (ColumnCount == 0) + return; - foreach (PropertyDescriptor property in properties) { - if (property.PropertyType == typeof (IBindingList)) - continue; + DataGridViewRow row = (DataGridViewRow)RowTemplateFull; + rows.InternalAdd (row); + + PropertyDescriptorCollection properties = TypeDescriptor.GetProperties (element); + + foreach (PropertyDescriptor property in properties) { + if (property.PropertyType == typeof (IBindingList)) + continue; + + // We do it this way because there may not be a column + // for every cell, ignore cells with no column + DataGridViewCell cell = row.Cells.GetBoundCell (property.Name); + + if (cell == null) + continue; - // We do it this way because there may not be a column - // for every cell, ignore cells with no column - DataGridViewCell cell = row.Cells[property.Name]; + cell.valuex = property.GetValue (element); + cell.valueType = property.PropertyType; + } + } + + private void GenerateColumnsFromType (Type type) + { + foreach (PropertyDescriptor property in TypeDescriptor.GetProperties (type)) { + // This keeps out things like arrays + if ((typeof(ICollection).IsAssignableFrom (property.PropertyType))) + continue; - if (cell == null) - continue; - - cell.valuex = property.GetValue (element); - cell.valueType = property.PropertyType; - } + DataGridViewColumn col = CreateColumnByType (property.PropertyType); + col.Name = property.DisplayName; + col.DataPropertyName = property.DisplayName; + col.ReadOnly = property.IsReadOnly; + col.SetIsDataBound (true); + col.ValueType = property.PropertyType; + col.AutoGenerated = true; + columns.Add (col); } } - + private DataGridViewColumn CreateColumnByType (Type type) { if (type == typeof (bool)) @@ -5451,14 +5867,34 @@ namespace System.Windows.Forms { private void ClearBinding () { + columns.ClearAutoGeneratedColumns (); + rows.Clear (); + PrepareEditingRow (false, true); + if (dataSource != null) { - columns.Clear (); - rows.Clear (); - - if (dataSource is DataView) + if (dataSource is DataSet) { + (dataSource as DataSet).Tables.CollectionChanged -= OnDataSetTableChanged; + + DataTable dt = (dataSource as DataSet).Tables[dataMember]; + + if (dt != null) { + DataView dv = dt.DefaultView; + + if (dv != null) { + (dv as DataView).Table.ColumnChanged -= OnTableColumnChanged; + (dv as DataView).ListChanged -= OnListChanged; + } + } + } else if (dataSource is DataView) { (dataSource as DataView).ListChanged -= OnListChanged; - if (dataSource is DataTable) + (dataSource as DataView).Table.ColumnChanged -= OnTableColumnChanged; + } else if (dataSource is DataTable) ((dataSource as IListSource).GetList () as DataView).ListChanged -= OnListChanged; + + if (dataSource is IBindingList) + (dataSource as IBindingList).ListChanged -= OnListChanged; + if (dataSource is BindingSource) + (dataSource as BindingSource).DataSourceChanged -= OnBindingSourceDataSourceChanged; } } @@ -5479,30 +5915,45 @@ namespace System.Windows.Forms { Invalidate (); return; } - if (value is DataSet) + if (value is DataSet) { + (value as DataSet).Tables.CollectionChanged += OnDataSetTableChanged; value = (value as DataSet).Tables[dataMember]; - - if (value is IList) + } + + if (value is BindingSource) + BindBindingSource (value as BindingSource); + else if (value is IBindingListView) + BindIBindingListView (value as IBindingListView); + else if (value is IBindingList) + BindIBindingList (value as IBindingList); + else if (value is IList) BindIList (value as IList); else if (value is IListSource) BindIListSource (value as IListSource); - else if (value is IBindingList) - BindIBindingList (value as IBindingList); - else if (value is IBindingListView) - BindIBindingListView (value as IBindingListView); OnDataBindingComplete (new DataGridViewBindingCompleteEventArgs (ListChangedType.Reset)); } + if (Rows.Count > 0 && Columns.Count > 0) + MoveCurrentCell (0, 0, true, false, false, false); + PerformLayout(); Invalidate (); } + private void BindBindingSource (BindingSource bindingSource) + { + BindIList (bindingSource.List); + bindingSource.ListChanged += OnBindingSourceDataSourceChanged; + bindingSource.DataSourceChanged += OnBindingSourceDataSourceChanged; + } + private void BindIListSource (IListSource list) { - BindIList(list.GetList()); + BindIList (list.GetList()); } private void BindIBindingList (IBindingList list) { - BindIList(list); + BindIList (list); + list.ListChanged += OnListChanged; } private void BindIBindingListView (IBindingListView list) { @@ -5511,6 +5962,9 @@ namespace System.Windows.Forms { private void MoveCurrentCell (int x, int y, bool select, bool isControl, bool isShift, bool scroll) { + if (!SetCurrentCellAddressCore (x, y, true, false, false)) + return; + bool full_row_selected = Rows.SharedRow(CurrentCellAddress.Y).Selected; bool full_col_selected = Columns[CurrentCellAddress.X].Selected; @@ -5529,9 +5983,6 @@ namespace System.Windows.Forms { else if (mode == DataGridViewSelectionMode.ColumnHeaderSelect) mode = DataGridViewSelectionMode.CellSelect; - // Move CurrentCell - SetCurrentCellAddressCore (x, y, true, false, false); - // If the current cell isn't visible, scroll to it if (scroll) { int disp_x = ColumnIndexToDisplayIndex (x); @@ -5550,10 +6001,10 @@ namespace System.Windows.Forms { } int disp_y = y; + int displayedRowsCount = DisplayedRowCount (false); + int delta_y = 0; if (disp_y < first_row_index) { - int delta_y = 0; - if (disp_y == 0) delta_y = verticalScrollBar.Value; else @@ -5562,13 +6013,11 @@ namespace System.Windows.Forms { verticalScrollBar.SafeValueSet (verticalScrollBar.Value - delta_y); OnVScrollBarScroll (this, new ScrollEventArgs (ScrollEventType.ThumbPosition, verticalScrollBar.Value)); - } else if (disp_y > first_row_index + DisplayedRowCount (false) - 2) { - int delta_y = 0; - + } else if (disp_y > first_row_index + displayedRowsCount - 1) { if (disp_y == Rows.Count - 1) delta_y = verticalScrollBar.Maximum - verticalScrollBar.Value; else - for (int i = first_row_index + DisplayedRowCount (false) - 2; i < disp_y; i++) + for (int i = first_row_index + displayedRowsCount - 1; i < disp_y; i++) delta_y += GetRowInternal (i).Height; verticalScrollBar.SafeValueSet (verticalScrollBar.Value + delta_y); @@ -5608,22 +6057,78 @@ namespace System.Windows.Forms { return Columns.ColumnDisplayIndexSortedArrayList[index].Index; } - private void OnListChanged (object sender, ListChangedEventArgs args) { - if (args.OldIndex >= 0) { - } - if (args.NewIndex >= 0) { - object element = (sender as DataView)[args.NewIndex]; - DataGridViewRow row = new DataGridViewRow(); - rows.InternalAdd(row); - PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(element); - foreach (PropertyDescriptor property in properties) { - DataGridViewTextBoxCell cell = new DataGridViewTextBoxCell(); - cell.Value = property.GetValue(element); - cell.ValueType = property.PropertyType; - row.Cells.Add(cell); - } - Invalidate(); + private void OnListChanged (object sender, ListChangedEventArgs args) + { + switch (args.ListChangedType) { + case ListChangedType.ItemAdded: + AddBoundRow ((sender as IBindingList)[args.NewIndex]); + break; + case ListChangedType.ItemDeleted: + Rows.RemoveAt (args.NewIndex); + break; + default: + ClearBinding (); + DoBinding (); + break; } + + Invalidate (); + } + + private void OnTableColumnChanged (object sender, DataColumnChangeEventArgs e) + { + ClearBinding (); + DoBinding (); + } + + private void OnDataSetTableChanged (object sender, CollectionChangeEventArgs e) + { + ClearBinding (); + DoBinding (); + } + + private void OnTableCleared (object sender, DataTableClearEventArgs e) + { + ClearBinding (); + DoBinding (); + } + + private bool MouseOverColumnResize (int col, int mousex) + { + if (!allowUserToResizeColumns) + return false; + + Rectangle col_bounds = GetCellDisplayRectangle (col, 0, false); + + if (mousex >= col_bounds.Right - 4 && mousex <= col_bounds.Right) + return true; + + return false; + } + + private bool MouseOverRowResize (int row, int mousey) + { + if (!allowUserToResizeRows) + return false; + + Rectangle row_bounds = GetCellDisplayRectangle (0, row, false); + + if (mousey >= row_bounds.Bottom - 4 && mousey <= row_bounds.Bottom) + return true; + + return false; + } + + private void DrawVerticalResizeLine (int x) + { + Rectangle splitter = new Rectangle (x, Bounds.Y + 3 + (ColumnHeadersVisible ? ColumnHeadersHeight : 0), 1, Bounds.Height - 3 - (ColumnHeadersVisible ? ColumnHeadersHeight : 0)); + XplatUI.DrawReversibleRectangle (Handle, splitter, 2); + } + + private void DrawHorizontalResizeLine (int y) + { + Rectangle splitter = new Rectangle (Bounds.X + 3 + (RowHeadersVisible ? RowHeadersWidth : 0), y, Bounds.Width - 3 + (RowHeadersVisible ? RowHeadersWidth : 0), 1); + XplatUI.DrawReversibleRectangle (Handle, splitter, 2); } #region Stuff for ToolTips @@ -5677,11 +6182,13 @@ namespace System.Windows.Forms { { int column; int direction = 1; - - public ColumnSorter (DataGridViewColumn column, ListSortDirection direction) + bool numeric_sort; + + public ColumnSorter (DataGridViewColumn column, ListSortDirection direction, bool numeric) { this.column = column.Index; - + this.numeric_sort = numeric; + if (direction == ListSortDirection.Descending) this.direction = -1; } @@ -5692,6 +6199,9 @@ namespace System.Windows.Forms { DataGridViewRow row1 = (DataGridViewRow)x; DataGridViewRow row2 = (DataGridViewRow)y; + if (row1.Cells[column].ValueType == typeof (DateTime) && row2.Cells[column].ValueType == typeof (DateTime)) + return DateTime.Compare ((DateTime)row1.Cells[column].valuex, (DateTime)row2.Cells[column].valuex) * direction; + object val1 = row1.Cells[column].FormattedValue; object val2 = row2.Cells[column].FormattedValue; @@ -5702,7 +6212,10 @@ namespace System.Windows.Forms { if (val2 == null) return -1 * direction; - return string.Compare (val1.ToString (), val2.ToString ()) * direction; + if (numeric_sort) + return (int)(double.Parse (val1.ToString ()) - double.Parse (val2.ToString ())) * direction; + else + return string.Compare (val1.ToString (), val2.ToString ()) * direction; } #endregion } @@ -5768,7 +6281,7 @@ namespace System.Windows.Forms { [ComVisible (false)] public class DataGridViewControlCollection : Control.ControlCollection { - private new DataGridView owner; + private DataGridView owner; public DataGridViewControlCollection (DataGridView owner) : base (owner) {