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>
29 using System.ComponentModel;
30 using System.Collections;
31 using System.ComponentModel.Design.Serialization;
33 namespace System.Windows.Forms
35 [DesignerSerializerAttribute ("System.Windows.Forms.Design.DataGridViewRowCollectionCodeDomSerializer, " + Consts.AssemblySystem_Design,
36 "System.ComponentModel.Design.Serialization.CodeDomSerializer, " + Consts.AssemblySystem_Design)]
37 [ListBindable (false)]
38 public class DataGridViewRowCollection : IList, ICollection, IEnumerable
40 private ArrayList list;
41 private DataGridView dataGridView;
42 private bool raiseEvent = true;
44 public DataGridViewRowCollection (DataGridView dataGridView)
46 this.dataGridView = dataGridView;
47 list = new ArrayList ();
51 get { return list.Count; }
54 int ICollection.Count {
58 bool IList.IsFixedSize {
59 get { return list.IsFixedSize; }
62 bool IList.IsReadOnly {
63 get { return list.IsReadOnly; }
66 bool ICollection.IsSynchronized {
67 get { return list.IsSynchronized; }
70 object IList.this [int index] {
74 set { list[index] = value as DataGridViewRow; }
77 public DataGridViewRow this [int index] {
79 // Accessing a System.Windows.Forms.DataGridViewRow with this indexer causes the row to become unshared.
80 // To keep the row shared, use the System.Windows.Forms.DataGridViewRowCollection.SharedRow method.
81 // For more information, see Best Practices for Scaling the Windows Forms DataGridView Control.
82 DataGridViewRow row = (DataGridViewRow) list [index];
83 if (row.Index == -1) {
84 row = (DataGridViewRow) row.Clone ();
92 object ICollection.SyncRoot {
93 get { return list.SyncRoot; }
96 public event CollectionChangeEventHandler CollectionChanged;
98 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
99 public virtual int Add ()
101 return Add (dataGridView.RowTemplateFull as DataGridViewRow);
104 int IList.Add (object value)
106 return Add (value as DataGridViewRow);
109 private int AddCore (DataGridViewRow dataGridViewRow, bool sharable)
111 if (dataGridView.Columns.Count == 0)
112 throw new InvalidOperationException ("DataGridView has no columns.");
116 dataGridViewRow.SetDataGridView (dataGridView);
119 // Add the row just before the editing row (if there is an editing row).
121 int editing_index = -1;
122 if (DataGridView != null && DataGridView.EditingRow != null && DataGridView.EditingRow != dataGridViewRow) {
123 editing_index = list.Count - 1; // always the last row
124 DataGridView.EditingRow.SetIndex (list.Count);
127 if (editing_index >= 0) {
128 list.Insert (editing_index, dataGridViewRow);
129 result = editing_index;
131 result = list.Add (dataGridViewRow);
134 if (sharable && CanBeShared (dataGridViewRow)) {
135 dataGridViewRow.SetIndex (-1);
137 dataGridViewRow.SetIndex (result);
140 CompleteRowCells (dataGridViewRow);
141 for (int i = 0; i < dataGridViewRow.Cells.Count; i++) {
142 dataGridViewRow.Cells [i].SetOwningColumn (dataGridView.Columns [i]);
146 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRow));
147 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (result, 1));
153 // Complete the rows if they are incomplete.
154 private void CompleteRowCells (DataGridViewRow row)
156 if (row == null || DataGridView == null)
159 if (row.Cells.Count < DataGridView.ColumnCount) {
160 for (int i = row.Cells.Count; i < DataGridView.ColumnCount; i++)
161 row.Cells.Add ((DataGridViewCell) DataGridView.Columns[i].CellTemplate.Clone ());
165 public virtual int Add (DataGridViewRow dataGridViewRow)
167 if (dataGridView.DataSource != null)
168 throw new InvalidOperationException ("DataSource of DataGridView is not null.");
169 return AddCore (dataGridViewRow, true);
172 private bool CanBeShared (DataGridViewRow row)
174 // We don't currently support shared rows
177 //foreach (DataGridViewCell cell in row.Cells) {
178 // if (cell.Value != null)
180 // if (cell.ToolTipText != string.Empty)
182 // if (cell.ContextMenuStrip != null)
190 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
191 public virtual int Add (int count)
194 throw new ArgumentOutOfRangeException("Count is less than or equeal to 0.");
195 if (dataGridView.DataSource != null)
196 throw new InvalidOperationException("DataSource of DataGridView is not null.");
197 if (dataGridView.Columns.Count == 0)
198 throw new InvalidOperationException("DataGridView has no columns.");
202 for (int i = 0; i < count; i++)
203 result = Add (dataGridView.RowTemplateFull as DataGridViewRow);
204 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (result - count + 1, count));
209 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
210 public virtual int Add (params object[] values)
213 throw new ArgumentNullException("values is null.");
214 if (dataGridView.VirtualMode)
215 throw new InvalidOperationException("DataGridView is in virtual mode.");
217 DataGridViewRow row = (DataGridViewRow)dataGridView.RowTemplateFull;
218 int result = AddCore (row, false);
219 row.SetValues(values);
223 public virtual int AddCopies (int indexSource, int count)
227 for (int i = 0; i < count; i++)
228 lastIndex = AddCopy(indexSource);
229 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (lastIndex - count + 1, count));
234 public virtual int AddCopy (int indexSource)
236 return Add ((list [indexSource] as DataGridViewRow).Clone () as DataGridViewRow);
239 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
240 public virtual void AddRange (params DataGridViewRow [] dataGridViewRows)
242 if (dataGridView.DataSource != null)
243 throw new InvalidOperationException ("DataSource of DataGridView is not null.");
248 foreach (DataGridViewRow row in dataGridViewRows) {
249 lastIndex = Add (row);
254 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (lastIndex - count + 1, count));
255 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRows));
258 public virtual void Clear ()
260 int total = list.Count;
262 DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (0, total));
264 for (int i = 0; i < total; i++) {
265 DataGridViewRow row = (DataGridViewRow)list[0];
267 // We can exit because the NewRow is always last
275 DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (0, total));
276 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null));
279 internal void ClearInternal ()
284 bool IList.Contains (object value)
286 return Contains (value as DataGridViewRow);
289 public virtual bool Contains (DataGridViewRow dataGridViewRow)
291 return list.Contains (dataGridViewRow);
294 void ICollection.CopyTo (Array array, int index)
296 list.CopyTo (array, index);
299 public void CopyTo (DataGridViewRow[] array, int index)
301 list.CopyTo (array, index);
304 IEnumerator IEnumerable.GetEnumerator ()
306 return list.GetEnumerator ();
309 public int GetFirstRow (DataGridViewElementStates includeFilter)
311 for (int i = 0; i < list.Count; i++) {
312 DataGridViewRow row = (DataGridViewRow) list [i];
313 if ((row.State & includeFilter) != 0)
319 public int GetFirstRow (DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
321 for (int i = 0; i < list.Count; i++) {
322 DataGridViewRow row = (DataGridViewRow) list [i];
323 if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0))
329 public int GetLastRow (DataGridViewElementStates includeFilter)
331 for (int i = list.Count - 1; i >= 0; i--) {
332 DataGridViewRow row = (DataGridViewRow) list [i];
333 if ((row.State & includeFilter) != 0)
339 public int GetNextRow (int indexStart, DataGridViewElementStates includeFilter)
341 for (int i = indexStart + 1; i < list.Count; i++) {
342 DataGridViewRow row = (DataGridViewRow) list [i];
343 if ((row.State & includeFilter) != 0)
349 public int GetNextRow (int indexStart, DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
351 for (int i = indexStart + 1; i < list.Count; i++) {
352 DataGridViewRow row = (DataGridViewRow) list [i];
353 if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0))
359 public int GetPreviousRow (int indexStart, DataGridViewElementStates includeFilter)
361 for (int i = indexStart - 1; i >= 0; i--) {
362 DataGridViewRow row = (DataGridViewRow) list [i];
363 if ((row.State & includeFilter) != 0)
369 public int GetPreviousRow (int indexStart, DataGridViewElementStates includeFilter, DataGridViewElementStates excludeFilter)
371 for (int i = indexStart - 1; i >= 0; i--) {
372 DataGridViewRow row = (DataGridViewRow) list [i];
373 if (((row.State & includeFilter) != 0) && ((row.State & excludeFilter) == 0))
379 public int GetRowCount (DataGridViewElementStates includeFilter)
382 foreach (DataGridViewRow row in list)
383 if ((row.State & includeFilter) != 0)
388 public int GetRowsHeight (DataGridViewElementStates includeFilter)
391 foreach (DataGridViewRow row in list)
392 if ((row.State & includeFilter) != 0)
393 result += row.Height;
397 public virtual DataGridViewElementStates GetRowState (int rowIndex)
399 return (list [rowIndex] as DataGridViewRow).State;
402 int IList.IndexOf (object value)
404 return IndexOf (value as DataGridViewRow);
407 public int IndexOf (DataGridViewRow dataGridViewRow)
409 return list.IndexOf (dataGridViewRow);
412 void IList.Insert (int index, object value)
414 Insert (index, value as DataGridViewRow);
417 // FIXME: Do *not* allow insertation *after* the editing row!
418 public virtual void Insert (int rowIndex, DataGridViewRow dataGridViewRow)
420 dataGridViewRow.SetIndex (rowIndex);
421 dataGridViewRow.SetDataGridView (dataGridView);
422 CompleteRowCells (dataGridViewRow);
423 list.Insert (rowIndex, dataGridViewRow);
425 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Add, dataGridViewRow));
427 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, 1));
430 public virtual void Insert (int rowIndex, int count)
432 int index = rowIndex;
434 for (int i = 0; i < count; i++)
435 Insert (index++, dataGridView.RowTemplateFull);
436 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, count));
440 public virtual void Insert (int rowIndex, params object[] values)
443 throw new ArgumentNullException ("Values is null.");
444 if (dataGridView.VirtualMode || dataGridView.DataSource != null)
445 throw new InvalidOperationException ();
446 DataGridViewRow row = new DataGridViewRow ();
447 row.SetValues (values);
448 Insert (rowIndex, row);
451 public virtual void InsertCopies (int indexSource, int indexDestination, int count)
454 int index = indexDestination;
455 for (int i = 0; i < count; i++)
456 InsertCopy (indexSource, index++);
457 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (indexDestination, count));
461 public virtual void InsertCopy (int indexSource, int indexDestination)
463 Insert (indexDestination, (list [indexSource] as DataGridViewRow).Clone());
466 public virtual void InsertRange (int rowIndex, params DataGridViewRow [] dataGridViewRows)
469 int index = rowIndex;
471 foreach (DataGridViewRow row in dataGridViewRows) {
472 Insert (index++, row);
475 DataGridView.OnRowsAddedInternal (new DataGridViewRowsAddedEventArgs (rowIndex, count));
479 void IList.Remove (object value)
481 Remove (value as DataGridViewRow);
484 public virtual void Remove (DataGridViewRow dataGridViewRow)
486 if (dataGridViewRow.IsNewRow)
487 throw new InvalidOperationException ("Cannot delete the new row");
489 DataGridView.OnRowsPreRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
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 list.Remove (dataGridViewRow);
501 OnCollectionChanged (new CollectionChangeEventArgs (CollectionChangeAction.Remove, dataGridViewRow));
502 DataGridView.OnRowsPostRemovedInternal (new DataGridViewRowsRemovedEventArgs (dataGridViewRow.Index, 1));
505 public virtual void RemoveAt (int index)
507 DataGridViewRow row = this [index];
512 internal void RemoveAtInternal (int index)
514 DataGridViewRow row = this [index];
516 RemoveInternal (row);
519 public DataGridViewRow SharedRow (int rowIndex)
521 return (DataGridViewRow) list [rowIndex];
524 internal int SharedRowIndexOf (DataGridViewRow row)
526 return list.IndexOf (row);
529 protected DataGridView DataGridView {
530 get { return dataGridView; }
533 protected ArrayList List {
537 protected virtual void OnCollectionChanged (CollectionChangeEventArgs e)
539 if (CollectionChanged != null)
540 CollectionChanged (this, e);
543 internal void AddInternal (DataGridViewRow dataGridViewRow, bool sharable)
546 AddCore (dataGridViewRow, sharable);
550 internal ArrayList RowIndexSortedArrayList {
552 ArrayList result = (ArrayList) list.Clone();
553 result.Sort(new RowIndexComparator());
558 internal void ReIndex ()
560 for (int i = 0; i < Count; i++)
561 (list[i] as DataGridViewRow).SetIndex (i);
564 internal void Sort (IComparer comparer)
566 // Note: you will probably want to call
567 // invalidate after using this.
568 if (DataGridView != null && DataGridView.EditingRow != null)
569 list.Sort (0, Count - 1, comparer);
571 list.Sort (comparer);
573 for (int i = 0; i < list.Count; i++)
574 (list[i] as DataGridViewRow).SetIndex (i);
577 private class RowIndexComparator : IComparer
579 public int Compare (object o1, object o2)
581 DataGridViewRow row1 = (DataGridViewRow) o1;
582 DataGridViewRow row2 = (DataGridViewRow) o2;
583 if (row1.Index < row2.Index) {
585 } else if (row1.Index > row2.Index) {