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 Novell, Inc. (http://www.novell.com)
23 // Pedro MartÃnez Juliá <pedromj@gmail.com>
27 using System.ComponentModel;
28 using System.Collections;
29 using System.ComponentModel.Design.Serialization;
31 namespace System.Windows.Forms
33 [DesignerSerializerAttribute ("System.Windows.Forms.Design.DataGridViewRowCollectionCodeDomSerializer, " + Consts.AssemblySystem_Design,
34 "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)]
35 [ListBindable (false)]
36 public class DataGridViewRowCollection : IList, ICollection, IEnumerable
38 private ArrayList list;
39 private DataGridView dataGridView;
40 private bool raiseEvent = true;
42 public DataGridViewRowCollection (DataGridView dataGridView)
44 this.dataGridView = dataGridView;
45 list = new ArrayList ();
49 get { return list.Count; }
52 int ICollection.Count {
56 bool IList.IsFixedSize {
57 get { return list.IsFixedSize; }
60 bool IList.IsReadOnly {
61 get { return list.IsReadOnly; }
64 bool ICollection.IsSynchronized {
65 get { return list.IsSynchronized; }
68 object IList.this [int index] {
72 set { list[index] = value as DataGridViewRow; }
75 public DataGridViewRow this [int index] {
77 // Accessing a System.Windows.Forms.DataGridViewRow with this indexer causes the row to become unshared.
78 // To keep the row shared, use the System.Windows.Forms.DataGridViewRowCollection.SharedRow method.
79 // For more information, see Best Practices for Scaling the Windows Forms DataGridView Control.
80 DataGridViewRow row = (DataGridViewRow) list [index];
81 if (row.Index == -1) {
82 row = (DataGridViewRow) row.Clone ();
90 object ICollection.SyncRoot {
91 get { return list.SyncRoot; }
94 public event CollectionChangeEventHandler CollectionChanged;
96 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
97 public virtual int Add ()
99 return Add (dataGridView.RowTemplateFull as DataGridViewRow);
102 int IList.Add (object value)
104 return Add (value as DataGridViewRow);
107 private int AddCore (DataGridViewRow dataGridViewRow, bool sharable)
109 if (dataGridView.Columns.Count == 0)
110 throw new InvalidOperationException ("DataGridView has no columns.");
114 dataGridViewRow.SetDataGridView (dataGridView);
117 // Add the row just before the editing row (if there is an editing row).
119 int editing_index = -1;
120 if (DataGridView != null && DataGridView.EditingRow != null && DataGridView.EditingRow != dataGridViewRow) {
121 editing_index = list.Count - 1; // always the last row
122 DataGridView.EditingRow.SetIndex (list.Count);
125 if (editing_index >= 0) {
126 list.Insert (editing_index, dataGridViewRow);
127 result = editing_index;
129 result = list.Add (dataGridViewRow);
132 if (sharable && CanBeShared (dataGridViewRow)) {
133 dataGridViewRow.SetIndex (-1);
135 dataGridViewRow.SetIndex (result);
138 CompleteRowCells (dataGridViewRow);
139 for (int i = 0; i < dataGridViewRow.Cells.Count; i++) {
140 dataGridViewRow.Cells [i].SetOwningColumn (dataGridView.Columns [i]);
144 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRow));
145 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (result, 1));
151 // Complete the rows if they are incomplete.
152 private void CompleteRowCells (DataGridViewRow row)
154 if (row == null || DataGridView == null)
157 if (row.Cells.Count < DataGridView.ColumnCount) {
158 for (int i = row.Cells.Count; i < DataGridView.ColumnCount; i++)
159 row.Cells.Add ((DataGridViewCell) DataGridView.Columns[i].CellTemplate.Clone ());
163 public virtual int Add (DataGridViewRow dataGridViewRow)
165 if (dataGridView.DataSource != null)
166 throw new InvalidOperationException ("DataSource of DataGridView is not null.");
167 return AddCore (dataGridViewRow, true);
170 private bool CanBeShared (DataGridViewRow row)
172 // We don't currently support shared rows
175 //foreach (DataGridViewCell cell in row.Cells) {
176 // if (cell.Value != null)
178 // if (cell.ToolTipText != string.Empty)
180 // if (cell.ContextMenuStrip != null)
188 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
189 public virtual int Add (int count)
192 throw new ArgumentOutOfRangeException("Count is less than or equeal to 0.");
193 if (dataGridView.DataSource != null)
194 throw new InvalidOperationException("DataSource of DataGridView is not null.");
195 if (dataGridView.Columns.Count == 0)
196 throw new InvalidOperationException("DataGridView has no columns.");
200 for (int i = 0; i < count; i++)
201 result = Add (dataGridView.RowTemplateFull as DataGridViewRow);
202 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (result - count + 1, count));
207 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
208 public virtual int Add (params object[] values)
211 throw new ArgumentNullException("values is null.");
212 if (dataGridView.VirtualMode)
213 throw new InvalidOperationException("DataGridView is in virtual mode.");
215 DataGridViewRow row = (DataGridViewRow)dataGridView.RowTemplateFull;
216 int result = AddCore (row, false);
217 row.SetValues(values);
221 public virtual int AddCopies (int indexSource, int count)
225 for (int i = 0; i < count; i++)
226 lastIndex = AddCopy(indexSource);
227 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (lastIndex - count + 1, count));
232 public virtual int AddCopy (int indexSource)
234 return Add ((list [indexSource] as DataGridViewRow).Clone () as DataGridViewRow);
237 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
238 public virtual void AddRange (params DataGridViewRow [] dataGridViewRows)
240 if (dataGridView.DataSource != null)
241 throw new InvalidOperationException ("DataSource of DataGridView is not null.");
246 foreach (DataGridViewRow row in dataGridViewRows) {
247 lastIndex = Add (row);
252 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (lastIndex - count + 1, count));
253 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRows));
256 public virtual void Clear ()
258 int total = list.Count;
260 DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (0, total));
262 for (int i = 0; i < total; i++) {
263 DataGridViewRow row = (DataGridViewRow)list[0];
265 // We can exit because the NewRow is always last
269 row.SetDataGridView (null);
274 DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (0, total));
275 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
278 internal void ClearInternal ()
283 bool IList.Contains (object value)
285 return Contains (value as DataGridViewRow);
288 public virtual bool Contains (DataGridViewRow dataGridViewRow)
290 return list.Contains (dataGridViewRow);
293 void ICollection.CopyTo (Array array, int index)
295 list.CopyTo (array, index);
298 public void CopyTo (DataGridViewRow[] array, int index)
300 list.CopyTo (array, index);
303 IEnumerator IEnumerable.GetEnumerator ()
305 return list.GetEnumerator ();
308 public int GetFirstRow (DataGridViewElementStates includeFilter)
310 for (int i = 0; i < list.Count; i++) {
311 DataGridViewRow row = (DataGridViewRow) list [i];
312 if ((row.State & includeFilter) != 0)
318 public int GetFirstRow (DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
320 for (int i = 0; i < list.Count; i++) {
321 DataGridViewRow row = (DataGridViewRow) list [i];
322 if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0))
328 public int GetLastRow (DataGridViewElementStates includeFilter)
330 for (int i = list.Count - 1; i >= 0; i--) {
331 DataGridViewRow row = (DataGridViewRow) list [i];
332 if ((row.State & includeFilter) != 0)
338 public int GetNextRow (int indexStart, DataGridViewElementStates includeFilter)
340 for (int i = indexStart + 1; i < list.Count; i++) {
341 DataGridViewRow row = (DataGridViewRow) list [i];
342 if ((row.State & includeFilter) != 0)
348 public int GetNextRow (int indexStart, DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
350 for (int i = indexStart + 1; i < list.Count; i++) {
351 DataGridViewRow row = (DataGridViewRow) list [i];
352 if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0))
358 public int GetPreviousRow (int indexStart, DataGridViewElementStates includeFilter)
360 for (int i = indexStart - 1; i >= 0; i--) {
361 DataGridViewRow row = (DataGridViewRow) list [i];
362 if ((row.State & includeFilter) != 0)
368 public int GetPreviousRow (int indexStart, DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
370 for (int i = indexStart - 1; i >= 0; i--) {
371 DataGridViewRow row = (DataGridViewRow) list [i];
372 if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0))
378 public int GetRowCount (DataGridViewElementStates includeFilter)
381 foreach (DataGridViewRow row in list)
382 if ((row.State & includeFilter) != 0)
387 public int GetRowsHeight (DataGridViewElementStates includeFilter)
390 foreach (DataGridViewRow row in list)
391 if ((row.State & includeFilter) != 0)
392 result += row.Height;
396 public virtual DataGridViewElementStates GetRowState (int rowIndex)
398 return (list [rowIndex] as DataGridViewRow).State;
401 int IList.IndexOf (object value)
403 return IndexOf (value as DataGridViewRow);
406 public int IndexOf (DataGridViewRow dataGridViewRow)
408 return list.IndexOf (dataGridViewRow);
411 void IList.Insert (int index, object value)
413 Insert (index, value as DataGridViewRow);
416 // FIXME: Do *not* allow insertation *after* the editing row!
417 public virtual void Insert (int rowIndex, DataGridViewRow dataGridViewRow)
419 dataGridViewRow.SetIndex (rowIndex);
420 dataGridViewRow.SetDataGridView (dataGridView);
421 CompleteRowCells (dataGridViewRow);
422 list.Insert (rowIndex, dataGridViewRow);
424 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRow));
426 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, 1));
429 public virtual void Insert (int rowIndex, int count)
431 int index = rowIndex;
433 for (int i = 0; i < count; i++)
434 Insert (index++, dataGridView.RowTemplateFull);
435 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, count));
439 public virtual void Insert (int rowIndex, params object[] values)
442 throw new ArgumentNullException ("Values is null.");
443 if (dataGridView.VirtualMode || dataGridView.DataSource != null)
444 throw new InvalidOperationException ();
445 DataGridViewRow row = dataGridView.RowTemplateFull;
446 row.SetValues (values);
447 Insert (rowIndex, row);
450 public virtual void InsertCopies (int indexSource, int indexDestination, int count)
453 int index = indexDestination;
454 for (int i = 0; i < count; i++)
455 InsertCopy (indexSource, index++);
456 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (indexDestination, count));
460 public virtual void InsertCopy (int indexSource, int indexDestination)
462 Insert (indexDestination, (list [indexSource] as DataGridViewRow).Clone());
465 public virtual void InsertRange (int rowIndex, params DataGridViewRow [] dataGridViewRows)
468 int index = rowIndex;
470 foreach (DataGridViewRow row in dataGridViewRows) {
471 Insert (index++, row);
474 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, count));
478 void IList.Remove (object value)
480 Remove (value as DataGridViewRow);
483 public virtual void Remove (DataGridViewRow dataGridViewRow)
485 if (dataGridViewRow.IsNewRow)
486 throw new InvalidOperationException ("Cannot delete the new row");
488 DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
489 dataGridViewRow.SetDataGridView (null);
490 list.Remove (dataGridViewRow);
492 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataGridViewRow));
493 DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
496 internal virtual void RemoveInternal (DataGridViewRow dataGridViewRow)
498 DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
499 dataGridViewRow.SetDataGridView (null);
500 list.Remove (dataGridViewRow);
502 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataGridViewRow));
503 DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
506 public virtual void RemoveAt (int index)
508 DataGridViewRow row = this [index];
513 internal void RemoveAtInternal (int index)
515 DataGridViewRow row = this [index];
517 RemoveInternal (row);
520 public DataGridViewRow SharedRow (int rowIndex)
522 return (DataGridViewRow) list [rowIndex];
525 internal int SharedRowIndexOf (DataGridViewRow row)
527 return list.IndexOf (row);
530 protected DataGridView DataGridView {
531 get { return dataGridView; }
534 protected ArrayList List {
538 protected virtual void OnCollectionChanged (CollectionChangeEventArgs e)
540 if (CollectionChanged != null)
541 CollectionChanged (this, e);
544 internal void AddInternal (DataGridViewRow dataGridViewRow, bool sharable)
547 AddCore (dataGridViewRow, sharable);
551 internal ArrayList RowIndexSortedArrayList {
553 ArrayList result = (ArrayList) list.Clone();
554 result.Sort(new RowIndexComparator());
559 internal void ReIndex ()
561 for (int i = 0; i < Count; i++)
562 (list[i] as DataGridViewRow).SetIndex (i);
565 internal void Sort (IComparer comparer)
567 // Note: you will probably want to call
568 // invalidate after using this.
569 if (DataGridView != null && DataGridView.EditingRow != null)
570 list.Sort (0, Count - 1, comparer);
572 list.Sort (comparer);
574 for (int i = 0; i < list.Count; i++)
575 (list[i] as DataGridViewRow).SetIndex (i);
578 private class RowIndexComparator : IComparer
580 public int Compare (object o1, object o2)
582 DataGridViewRow row1 = (DataGridViewRow) o1;
583 DataGridViewRow row2 = (DataGridViewRow) o2;
584 if (row1.Index < row2.Index) {
586 } else if (row1.Index > row2.Index) {