// // System.Data.DataColumnCollection.cs // // Author: // Christopher Podurgiel (cpodurgiel@msn.com) // Stuart Caborn // Tim Coleman (tim@timcoleman.com) // // (C) Chris Podurgiel // Copyright (C) Tim Coleman, 2002 // Copyright (C) Daniel Morgan, 2003 // using System; using System.Collections; using System.ComponentModel; namespace System.Data { [Editor] [Serializable] [DefaultEvent ("CollectionChanged")] public class DataColumnCollection : InternalDataCollectionBase { //table should be the DataTable this DataColumnCollection belongs to. private DataTable parentTable = null; // Internal Constructor. This Class can only be created from other classes in this assembly. internal DataColumnCollection(DataTable table):base() { parentTable = table; } /// /// Gets the DataColumn from the collection at the specified index. /// public virtual DataColumn this[int index] { get { return (DataColumn) base.List[index]; } } /// /// Gets the DataColumn from the collection with the specified name. /// public virtual DataColumn this[string name] { get { int tmp = IndexOf(name, true); if (tmp == -1) return null; return this[tmp]; } } /// /// Gets a list of the DataColumnCollection items. /// protected override ArrayList List { get { return base.List; } } //Add Logic // //Changing Event //DefaultValue set and AutoInc set check //?Validate Expression?? //Name check and creation //Set Table //Check Unique if true then add a unique constraint //?Notify Rows of new column ? //Add to collection //Changed Event /// /// Creates and adds a DataColumn object to the DataColumnCollection. /// /// public virtual DataColumn Add() { //FIXME: string defaultName = GetNextDefaultColumnName (); DataColumn column = new DataColumn (defaultName); CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this); column.SetTable(parentTable); base.List.Add(column); column.SetOrdinal(Count - 1); OnCollectionChanged(e); return column; } private string GetNextDefaultColumnName () { string defColumnName = "Column1"; for (int index = 2; Contains (defColumnName); ++index) { defColumnName = "Column" + index; } return defColumnName; } /// /// Creates and adds the specified DataColumn object to the DataColumnCollection. /// /// The DataColumn to add. [MonoTODO] public void Add(DataColumn column) { if (column == null) throw new ArgumentNullException ("column", "'column' argument cannot be null."); if (column.ColumnName.Equals(String.Empty)) { column.ColumnName = GetNextDefaultColumnName (); } int tmp = IndexOf(column.ColumnName); // if we found a column with same name we have to check // that it is the same case. // indexof can return a table with different case letters. if (tmp != -1) { if(column.ColumnName == this[tmp].ColumnName) throw new DuplicateNameException("A DataColumn named '" + column.ColumnName + "' already belongs to this DataTable."); } if (column.Table != null) throw new ArgumentException ("Column '" + column.ColumnName + "' already belongs to another DataTable."); CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this); column.SetTable (parentTable); int ordinal = base.List.Add(column); column.SetOrdinal (ordinal); if (column.AutoIncrement) { long value = column.AutoIncrementSeed; for (int i = 0; i < column.Table.Rows.Count; i++, value += column.AutoIncrementStep) column.Table.Rows [i] [ordinal] = value; } OnCollectionChanged (e); } /// /// Creates and adds a DataColumn object with the specified name to the DataColumnCollection. /// /// The name of the column. /// The newly created DataColumn. public virtual DataColumn Add(string columnName) { if (columnName == null || columnName == String.Empty) { columnName = GetNextDefaultColumnName (); } DataColumn column = new DataColumn(columnName); Add (column); return column; } /// /// Creates and adds a DataColumn object with the specified name and type to the DataColumnCollection. /// /// The ColumnName to use when cretaing the column. /// The DataType of the new column. /// The newly created DataColumn. public virtual DataColumn Add(string columnName, Type type) { if (columnName == null || columnName == "") { columnName = GetNextDefaultColumnName (); } DataColumn column = new DataColumn(columnName, type); Add (column); return column; } /// /// Creates and adds a DataColumn object with the specified name, type, and expression to the DataColumnCollection. /// /// The name to use when creating the column. /// The DataType of the new column. /// The expression to assign to the Expression property. /// The newly created DataColumn. public virtual DataColumn Add(string columnName, Type type, string expression) { if (columnName == null || columnName == "") { columnName = GetNextDefaultColumnName (); } DataColumn column = new DataColumn(columnName, type, expression); Add (column); return column; } /// /// Copies the elements of the specified DataColumn array to the end of the collection. /// /// The array of DataColumn objects to add to the collection. public void AddRange(DataColumn[] columns) { foreach (DataColumn column in columns) { Add(column); } return; } /// /// Checks whether a given column can be removed from the collection. /// /// A DataColumn in the collection. /// true if the column can be removed; otherwise, false. public bool CanRemove(DataColumn column) { //Check that the column does not have a null reference. if (column == null) { return false; } //Check that the column is part of this collection. if (!Contains(column.ColumnName)) { return false; } //Check if this column is part of a relationship. (this could probably be written better) foreach (DataRelation childRelation in parentTable.ChildRelations) { foreach (DataColumn childColumn in childRelation.ChildColumns) { if (childColumn == column) { return false; } } foreach (DataColumn parentColumn in childRelation.ParentColumns) { if (parentColumn == column) { return false; } } } //Check if this column is part of a relationship. (this could probably be written better) foreach (DataRelation parentRelation in parentTable.ParentRelations) { foreach (DataColumn childColumn in parentRelation.ChildColumns) { if (childColumn == column) { return false; } } foreach (DataColumn parentColumn in parentRelation.ParentColumns) { if (parentColumn == column) { return false; } } } //Check if another column's expression depends on this column. foreach (DataColumn dataColumn in List) { if (dataColumn.Expression.ToString().IndexOf(column.ColumnName) > 0) { return false; } } //TODO: check constraints return true; } /// /// Clears the collection of any columns. /// public void Clear() { CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this); // FIXME: Hmm... This loop could look little nicer :) foreach (DataColumn Col in List) { foreach (DataRelation Rel in Col.Table.ParentRelations) { foreach (DataColumn Col2 in Rel.ParentColumns) { if (Object.ReferenceEquals (Col, Col2)) throw new ArgumentException ("Cannot remove this column, because " + "it is part of the parent key for relationship " + Rel.RelationName + "."); } foreach (DataColumn Col2 in Rel.ChildColumns) { if (Object.ReferenceEquals (Col, Col2)) throw new ArgumentException ("Cannot remove this column, because " + "it is part of the parent key for relationship " + Rel.RelationName + "."); } } foreach (DataRelation Rel in Col.Table.ChildRelations) { foreach (DataColumn Col2 in Rel.ParentColumns) { if (Object.ReferenceEquals (Col, Col2)) throw new ArgumentException ("Cannot remove this column, because " + "it is part of the parent key for relationship " + Rel.RelationName + "."); } foreach (DataColumn Col2 in Rel.ChildColumns) { if (Object.ReferenceEquals (Col, Col2)) throw new ArgumentException ("Cannot remove this column, because " + "it is part of the parent key for relationship " + Rel.RelationName + "."); } } } base.List.Clear(); OnCollectionChanged(e); return; } /// /// Checks whether the collection contains a column with the specified name. /// /// The ColumnName of the column to check for. /// true if a column exists with this name; otherwise, false. public bool Contains(string name) { return (IndexOf(name, false) != -1); } /// /// Gets the index of a column specified by name. /// /// The name of the column to return. /// The index of the column specified by column if it is found; otherwise, -1. public virtual int IndexOf(DataColumn column) { return base.List.IndexOf(column); } /// /// Gets the index of the column with the given name (the name is not case sensitive). /// /// The name of the column to find. /// The zero-based index of the column with the specified name, or -1 if the column doesn't exist in the collection. public int IndexOf(string columnName) { return IndexOf(columnName, false); } /// /// Raises the OnCollectionChanged event. /// /// A CollectionChangeEventArgs that contains the event data. protected virtual void OnCollectionChanged(CollectionChangeEventArgs ccevent) { if (CollectionChanged != null) { CollectionChanged(this, ccevent); } } /// /// Raises the OnCollectionChanging event. /// /// A CollectionChangeEventArgs that contains the event data. protected internal virtual void OnCollectionChanging(CollectionChangeEventArgs ccevent) { if (CollectionChanged != null) { //FIXME: this is not right //CollectionChanged(this, ccevent); throw new NotImplementedException(); } } /// /// Removes the specified DataColumn object from the collection. /// /// The DataColumn to remove. public void Remove(DataColumn column) { if (IndexOf (column) == -1) throw new ArgumentException ("Cannot remove a column that doesn't belong to this table."); //TODO: can remove first with exceptions //and OnChanging Event CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Remove, this); int ordinal = column.Ordinal; base.List.Remove(column); //Update the ordinals for( int i = ordinal ; i < this.Count ; i ++ ) { this[i].SetOrdinal( i ); } OnCollectionChanged(e); return; } /// /// Removes the DataColumn object with the specified name from the collection. /// /// The name of the column to remove. public void Remove(string name) { DataColumn column = this[name]; if (column == null) throw new ArgumentException ("Column '" + name + "' does not belong to table test_table."); Remove( column ); } /// /// Removes the column at the specified index from the collection. /// /// The index of the column to remove. public void RemoveAt(int index) { if (Count <= index) throw new IndexOutOfRangeException ("Cannot find column " + index + "."); DataColumn column = this[index]; Remove( column ); } /// /// Do the same as Constains -method but case sensitive /// private bool CaseSensitiveContains(string columnName) { DataColumn column = this[columnName]; if (column != null) return string.Compare (column.ColumnName, columnName, false) == 0; return false; } private int IndexOf (string name, bool error) { int count = 0, match = -1; for (int i = 0; i < List.Count; i++) { String name2 = ((DataColumn) List[i]).ColumnName; if (String.Compare (name, name2, true) == 0) { if (String.Compare (name, name2, false) == 0) return i; match = i; count++; } } if (count == 1) return match; if (count > 1 && error) throw new ArgumentException ("There is no match for the name in the same case and there are multiple matches in different case."); return -1; } /// /// Occurs when the columns collection changes, either by adding or removing a column. /// public event CollectionChangeEventHandler CollectionChanged; } }