// Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // // Copyright (c) 2005 Novell, Inc. (http://www.novell.com) // // Author: // Pedro Martínez Juliá // using System.ComponentModel; using System.Collections; using System.ComponentModel.Design.Serialization; namespace System.Windows.Forms { [DesignerSerializerAttribute ("System.Windows.Forms.Design.DataGridViewRowCollectionCodeDomSerializer, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)] [ListBindable (false)] public class DataGridViewRowCollection : IList, ICollection, IEnumerable { private ArrayList list; private DataGridView dataGridView; private bool raiseEvent = true; public DataGridViewRowCollection (DataGridView dataGridView) { this.dataGridView = dataGridView; list = new ArrayList (); } public int Count { get { return list.Count; } } int ICollection.Count { get { return Count; } } bool IList.IsFixedSize { get { return list.IsFixedSize; } } bool IList.IsReadOnly { get { return list.IsReadOnly; } } bool ICollection.IsSynchronized { get { return list.IsSynchronized; } } object IList.this [int index] { get { return this[index]; } set { list[index] = value as DataGridViewRow; } } public DataGridViewRow this [int index] { get { // Accessing a System.Windows.Forms.DataGridViewRow with this indexer causes the row to become unshared. // To keep the row shared, use the System.Windows.Forms.DataGridViewRowCollection.SharedRow method. // For more information, see Best Practices for Scaling the Windows Forms DataGridView Control. DataGridViewRow row = (DataGridViewRow) list [index]; if (row.Index == -1) { row = (DataGridViewRow) row.Clone (); row.SetIndex (index); list [index] = row; } return row; } } object ICollection.SyncRoot { get { return list.SyncRoot; } } public event CollectionChangeEventHandler CollectionChanged; [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public virtual int Add () { return Add (dataGridView.RowTemplateFull as DataGridViewRow); } int IList.Add (object value) { return Add (value as DataGridViewRow); } private int AddCore (DataGridViewRow dataGridViewRow, bool sharable) { if (dataGridView.Columns.Count == 0) throw new InvalidOperationException ("DataGridView has no columns."); int result; dataGridViewRow.SetDataGridView (dataGridView); // // Add the row just before the editing row (if there is an editing row). // int editing_index = -1; if (DataGridView != null && DataGridView.EditingRow != null && DataGridView.EditingRow != dataGridViewRow) { editing_index = list.Count - 1; // always the last row DataGridView.EditingRow.SetIndex (list.Count); } if (editing_index >= 0) { list.Insert (editing_index, dataGridViewRow); result = editing_index; } else { result = list.Add (dataGridViewRow); } if (sharable && CanBeShared (dataGridViewRow)) { dataGridViewRow.SetIndex (-1); } else { dataGridViewRow.SetIndex (result); } CompleteRowCells (dataGridViewRow); for (int i = 0; i < dataGridViewRow.Cells.Count; i++) { dataGridViewRow.Cells [i].SetOwningColumn (dataGridView.Columns [i]); } if (raiseEvent) { OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRow)); DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (result, 1)); } return result; } // Complete the rows if they are incomplete. private void CompleteRowCells (DataGridViewRow row) { if (row == null || DataGridView == null) return; if (row.Cells.Count < DataGridView.ColumnCount) { for (int i = row.Cells.Count; i < DataGridView.ColumnCount; i++) row.Cells.Add ((DataGridViewCell) DataGridView.Columns[i].CellTemplate.Clone ()); } } public virtual int Add (DataGridViewRow dataGridViewRow) { if (dataGridView.DataSource != null) throw new InvalidOperationException ("DataSource of DataGridView is not null."); return AddCore (dataGridViewRow, true); } private bool CanBeShared (DataGridViewRow row) { // We don't currently support shared rows return false; //foreach (DataGridViewCell cell in row.Cells) { // if (cell.Value != null) // return false; // if (cell.ToolTipText != string.Empty) // return false; // if (cell.ContextMenuStrip != null) // return false; //} //return true; } [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public virtual int Add (int count) { if (count <= 0) throw new ArgumentOutOfRangeException("Count is less than or equeal to 0."); if (dataGridView.DataSource != null) throw new InvalidOperationException("DataSource of DataGridView is not null."); if (dataGridView.Columns.Count == 0) throw new InvalidOperationException("DataGridView has no columns."); raiseEvent = false; int result = 0; for (int i = 0; i < count; i++) result = Add (dataGridView.RowTemplateFull as DataGridViewRow); DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (result - count + 1, count)); raiseEvent = true; return result; } [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public virtual int Add (params object[] values) { if (values == null) throw new ArgumentNullException("values is null."); if (dataGridView.VirtualMode) throw new InvalidOperationException("DataGridView is in virtual mode."); DataGridViewRow row = (DataGridViewRow)dataGridView.RowTemplateFull; int result = AddCore (row, false); row.SetValues(values); return result; } public virtual int AddCopies (int indexSource, int count) { raiseEvent = false; int lastIndex = 0; for (int i = 0; i < count; i++) lastIndex = AddCopy(indexSource); DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (lastIndex - count + 1, count)); raiseEvent = true; return lastIndex; } public virtual int AddCopy (int indexSource) { return Add ((list [indexSource] as DataGridViewRow).Clone () as DataGridViewRow); } [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public virtual void AddRange (params DataGridViewRow [] dataGridViewRows) { if (dataGridView.DataSource != null) throw new InvalidOperationException ("DataSource of DataGridView is not null."); int count = 0; int lastIndex = -1; raiseEvent = false; foreach (DataGridViewRow row in dataGridViewRows) { lastIndex = Add (row); count++; } raiseEvent = true; DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (lastIndex - count + 1, count)); OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRows)); } public virtual void Clear () { int total = list.Count; DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (0, total)); for (int i = 0; i < total; i++) { DataGridViewRow row = (DataGridViewRow)list[0]; // We can exit because the NewRow is always last if (row.IsNewRow) break; list.Remove (row); ReIndex (); } DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (0, total)); OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null)); } internal void ClearInternal () { list.Clear (); } bool IList.Contains (object value) { return Contains (value as DataGridViewRow); } public virtual bool Contains (DataGridViewRow dataGridViewRow) { return list.Contains (dataGridViewRow); } void ICollection.CopyTo (Array array, int index) { list.CopyTo (array, index); } public void CopyTo (DataGridViewRow[] array, int index) { list.CopyTo (array, index); } IEnumerator IEnumerable.GetEnumerator () { return list.GetEnumerator (); } public int GetFirstRow (DataGridViewElementStates includeFilter) { for (int i = 0; i < list.Count; i++) { DataGridViewRow row = (DataGridViewRow) list [i]; if ((row.State & includeFilter) != 0) return i; } return -1; } public int GetFirstRow (DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter) { for (int i = 0; i < list.Count; i++) { DataGridViewRow row = (DataGridViewRow) list [i]; if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0)) return i; } return -1; } public int GetLastRow (DataGridViewElementStates includeFilter) { for (int i = list.Count - 1; i >= 0; i--) { DataGridViewRow row = (DataGridViewRow) list [i]; if ((row.State & includeFilter) != 0) return i; } return -1; } public int GetNextRow (int indexStart, DataGridViewElementStates includeFilter) { for (int i = indexStart + 1; i < list.Count; i++) { DataGridViewRow row = (DataGridViewRow) list [i]; if ((row.State & includeFilter) != 0) return i; } return -1; } public int GetNextRow (int indexStart, DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter) { for (int i = indexStart + 1; i < list.Count; i++) { DataGridViewRow row = (DataGridViewRow) list [i]; if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0)) return i; } return -1; } public int GetPreviousRow (int indexStart, DataGridViewElementStates includeFilter) { for (int i = indexStart - 1; i >= 0; i--) { DataGridViewRow row = (DataGridViewRow) list [i]; if ((row.State & includeFilter) != 0) return i; } return -1; } public int GetPreviousRow (int indexStart, DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter) { for (int i = indexStart - 1; i >= 0; i--) { DataGridViewRow row = (DataGridViewRow) list [i]; if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0)) return i; } return -1; } public int GetRowCount (DataGridViewElementStates includeFilter) { int result = 0; foreach (DataGridViewRow row in list) if ((row.State & includeFilter) != 0) result ++; return result; } public int GetRowsHeight (DataGridViewElementStates includeFilter) { int result = 0; foreach (DataGridViewRow row in list) if ((row.State & includeFilter) != 0) result += row.Height; return result; } public virtual DataGridViewElementStates GetRowState (int rowIndex) { return (list [rowIndex] as DataGridViewRow).State; } int IList.IndexOf (object value) { return IndexOf (value as DataGridViewRow); } public int IndexOf (DataGridViewRow dataGridViewRow) { return list.IndexOf (dataGridViewRow); } void IList.Insert (int index, object value) { Insert (index, value as DataGridViewRow); } // FIXME: Do *not* allow insertation *after* the editing row! public virtual void Insert (int rowIndex, DataGridViewRow dataGridViewRow) { dataGridViewRow.SetIndex (rowIndex); dataGridViewRow.SetDataGridView (dataGridView); CompleteRowCells (dataGridViewRow); list.Insert (rowIndex, dataGridViewRow); ReIndex (); OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRow)); if (raiseEvent) DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, 1)); } public virtual void Insert (int rowIndex, int count) { int index = rowIndex; raiseEvent = false; for (int i = 0; i < count; i++) Insert (index++, dataGridView.RowTemplateFull); DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, count)); raiseEvent = true; } public virtual void Insert (int rowIndex, params object[] values) { if (values == null) throw new ArgumentNullException ("Values is null."); if (dataGridView.VirtualMode || dataGridView.DataSource != null) throw new InvalidOperationException (); DataGridViewRow row = dataGridView.RowTemplateFull; row.SetValues (values); Insert (rowIndex, row); } public virtual void InsertCopies (int indexSource, int indexDestination, int count) { raiseEvent = false; int index = indexDestination; for (int i = 0; i < count; i++) InsertCopy (indexSource, index++); DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (indexDestination, count)); raiseEvent = true; } public virtual void InsertCopy (int indexSource, int indexDestination) { Insert (indexDestination, (list [indexSource] as DataGridViewRow).Clone()); } public virtual void InsertRange (int rowIndex, params DataGridViewRow [] dataGridViewRows) { raiseEvent = false; int index = rowIndex; int count = 0; foreach (DataGridViewRow row in dataGridViewRows) { Insert (index++, row); count++; } DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, count)); raiseEvent = true; } void IList.Remove (object value) { Remove (value as DataGridViewRow); } public virtual void Remove (DataGridViewRow dataGridViewRow) { if (dataGridViewRow.IsNewRow) throw new InvalidOperationException ("Cannot delete the new row"); DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1)); list.Remove (dataGridViewRow); ReIndex (); OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataGridViewRow)); DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1)); } internal virtual void RemoveInternal (DataGridViewRow dataGridViewRow) { DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1)); list.Remove (dataGridViewRow); ReIndex (); OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataGridViewRow)); DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1)); } public virtual void RemoveAt (int index) { DataGridViewRow row = this [index]; Remove (row); } internal void RemoveAtInternal (int index) { DataGridViewRow row = this [index]; RemoveInternal (row); } public DataGridViewRow SharedRow (int rowIndex) { return (DataGridViewRow) list [rowIndex]; } internal int SharedRowIndexOf (DataGridViewRow row) { return list.IndexOf (row); } protected DataGridView DataGridView { get { return dataGridView; } } protected ArrayList List { get { return list; } } protected virtual void OnCollectionChanged (CollectionChangeEventArgs e) { if (CollectionChanged != null) CollectionChanged (this, e); } internal void AddInternal (DataGridViewRow dataGridViewRow, bool sharable) { raiseEvent = false; AddCore (dataGridViewRow, sharable); raiseEvent = true; } internal ArrayList RowIndexSortedArrayList { get { ArrayList result = (ArrayList) list.Clone(); result.Sort(new RowIndexComparator()); return result; } } internal void ReIndex () { for (int i = 0; i < Count; i++) (list[i] as DataGridViewRow).SetIndex (i); } internal void Sort (IComparer comparer) { // Note: you will probably want to call // invalidate after using this. if (DataGridView != null && DataGridView.EditingRow != null) list.Sort (0, Count - 1, comparer); else list.Sort (comparer); for (int i = 0; i < list.Count; i++) (list[i] as DataGridViewRow).SetIndex (i); } private class RowIndexComparator : IComparer { public int Compare (object o1, object o2) { DataGridViewRow row1 = (DataGridViewRow) o1; DataGridViewRow row2 = (DataGridViewRow) o2; if (row1.Index < row2.Index) { return -1; } else if (row1.Index > row2.Index) { return 1; } else { return 0; } } } } }