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
273 DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (0, total));
274 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
277 internal void ClearInternal ()
282 bool IList.Contains (object value)
284 return Contains (value as DataGridViewRow);
287 public virtual bool Contains (DataGridViewRow dataGridViewRow)
289 return list.Contains (dataGridViewRow);
292 void ICollection.CopyTo (Array array, int index)
294 list.CopyTo (array, index);
297 public void CopyTo (DataGridViewRow[] array, int index)
299 list.CopyTo (array, index);
302 IEnumerator IEnumerable.GetEnumerator ()
304 return list.GetEnumerator ();
307 public int GetFirstRow (DataGridViewElementStates includeFilter)
309 for (int i = 0; i < list.Count; i++) {
310 DataGridViewRow row = (DataGridViewRow) list [i];
311 if ((row.State & includeFilter) != 0)
317 public int GetFirstRow (DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
319 for (int i = 0; i < list.Count; i++) {
320 DataGridViewRow row = (DataGridViewRow) list [i];
321 if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0))
327 public int GetLastRow (DataGridViewElementStates includeFilter)
329 for (int i = list.Count - 1; i >= 0; i--) {
330 DataGridViewRow row = (DataGridViewRow) list [i];
331 if ((row.State & includeFilter) != 0)
337 public int GetNextRow (int indexStart, DataGridViewElementStates includeFilter)
339 for (int i = indexStart + 1; i < list.Count; i++) {
340 DataGridViewRow row = (DataGridViewRow) list [i];
341 if ((row.State & includeFilter) != 0)
347 public int GetNextRow (int indexStart, DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
349 for (int i = indexStart + 1; i < list.Count; i++) {
350 DataGridViewRow row = (DataGridViewRow) list [i];
351 if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0))
357 public int GetPreviousRow (int indexStart, DataGridViewElementStates includeFilter)
359 for (int i = indexStart - 1; i >= 0; i--) {
360 DataGridViewRow row = (DataGridViewRow) list [i];
361 if ((row.State & includeFilter) != 0)
367 public int GetPreviousRow (int indexStart, DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
369 for (int i = indexStart - 1; i >= 0; i--) {
370 DataGridViewRow row = (DataGridViewRow) list [i];
371 if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0))
377 public int GetRowCount (DataGridViewElementStates includeFilter)
380 foreach (DataGridViewRow row in list)
381 if ((row.State & includeFilter) != 0)
386 public int GetRowsHeight (DataGridViewElementStates includeFilter)
389 foreach (DataGridViewRow row in list)
390 if ((row.State & includeFilter) != 0)
391 result += row.Height;
395 public virtual DataGridViewElementStates GetRowState (int rowIndex)
397 return (list [rowIndex] as DataGridViewRow).State;
400 int IList.IndexOf (object value)
402 return IndexOf (value as DataGridViewRow);
405 public int IndexOf (DataGridViewRow dataGridViewRow)
407 return list.IndexOf (dataGridViewRow);
410 void IList.Insert (int index, object value)
412 Insert (index, value as DataGridViewRow);
415 // FIXME: Do *not* allow insertation *after* the editing row!
416 public virtual void Insert (int rowIndex, DataGridViewRow dataGridViewRow)
418 dataGridViewRow.SetIndex (rowIndex);
419 dataGridViewRow.SetDataGridView (dataGridView);
420 CompleteRowCells (dataGridViewRow);
421 list.Insert (rowIndex, dataGridViewRow);
423 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRow));
425 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, 1));
428 public virtual void Insert (int rowIndex, int count)
430 int index = rowIndex;
432 for (int i = 0; i < count; i++)
433 Insert (index++, dataGridView.RowTemplateFull);
434 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, count));
438 public virtual void Insert (int rowIndex, params object[] values)
441 throw new ArgumentNullException ("Values is null.");
442 if (dataGridView.VirtualMode || dataGridView.DataSource != null)
443 throw new InvalidOperationException ();
444 DataGridViewRow row = dataGridView.RowTemplateFull;
445 row.SetValues (values);
446 Insert (rowIndex, row);
449 public virtual void InsertCopies (int indexSource, int indexDestination, int count)
452 int index = indexDestination;
453 for (int i = 0; i < count; i++)
454 InsertCopy (indexSource, index++);
455 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (indexDestination, count));
459 public virtual void InsertCopy (int indexSource, int indexDestination)
461 Insert (indexDestination, (list [indexSource] as DataGridViewRow).Clone());
464 public virtual void InsertRange (int rowIndex, params DataGridViewRow [] dataGridViewRows)
467 int index = rowIndex;
469 foreach (DataGridViewRow row in dataGridViewRows) {
470 Insert (index++, row);
473 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, count));
477 void IList.Remove (object value)
479 Remove (value as DataGridViewRow);
482 public virtual void Remove (DataGridViewRow dataGridViewRow)
484 if (dataGridViewRow.IsNewRow)
485 throw new InvalidOperationException ("Cannot delete the new row");
487 DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
488 list.Remove (dataGridViewRow);
490 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataGridViewRow));
491 DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
494 internal virtual void RemoveInternal (DataGridViewRow dataGridViewRow)
496 DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
497 list.Remove (dataGridViewRow);
499 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataGridViewRow));
500 DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
503 public virtual void RemoveAt (int index)
505 DataGridViewRow row = this [index];
510 internal void RemoveAtInternal (int index)
512 DataGridViewRow row = this [index];
514 RemoveInternal (row);
517 public DataGridViewRow SharedRow (int rowIndex)
519 return (DataGridViewRow) list [rowIndex];
522 internal int SharedRowIndexOf (DataGridViewRow row)
524 return list.IndexOf (row);
527 protected DataGridView DataGridView {
528 get { return dataGridView; }
531 protected ArrayList List {
535 protected virtual void OnCollectionChanged (CollectionChangeEventArgs e)
537 if (CollectionChanged != null)
538 CollectionChanged (this, e);
541 internal void AddInternal (DataGridViewRow dataGridViewRow, bool sharable)
544 AddCore (dataGridViewRow, sharable);
548 internal ArrayList RowIndexSortedArrayList {
550 ArrayList result = (ArrayList) list.Clone();
551 result.Sort(new RowIndexComparator());
556 internal void ReIndex ()
558 for (int i = 0; i < Count; i++)
559 (list[i] as DataGridViewRow).SetIndex (i);
562 internal void Sort (IComparer comparer)
564 // Note: you will probably want to call
565 // invalidate after using this.
566 if (DataGridView != null && DataGridView.EditingRow != null)
567 list.Sort (0, Count - 1, comparer);
569 list.Sort (comparer);
571 for (int i = 0; i < list.Count; i++)
572 (list[i] as DataGridViewRow).SetIndex (i);
575 private class RowIndexComparator : IComparer
577 public int Compare (object o1, object o2)
579 DataGridViewRow row1 = (DataGridViewRow) o1;
580 DataGridViewRow row2 = (DataGridViewRow) o2;
581 if (row1.Index < row2.Index) {
583 } else if (row1.Index > row2.Index) {