2 // System.Data.DataView.cs
\r
5 // Daniel Morgan <danmorg@sc.rr.com>
\r
6 // Tim Coleman (tim@timcoleman.com)
\r
7 // Punit Todi (punits_mailbox@yahoo.com)
\r
8 // Atsushi Enomoto <atsushi@ximian.com>
\r
9 // Konstantin Triger (kostat@mainsoft.com)
\r
11 // Copyright (C) Daniel Morgan, 2002, 2003
\r
12 // (C) Ximian, Inc 2002
\r
13 // Copyright (C) Tim Coleman, 2002-2003
\r
16 using System.Collections;
\r
17 using System.ComponentModel;
\r
18 using System.Reflection;
\r
19 using System.Data.Common;
\r
20 using System.Globalization;
\r
21 using Mono.Data.SqlExpressions;
\r
24 namespace System.Data
\r
27 /// A DataView is used in the binding of data between
\r
28 /// a DataTable and Windows Forms or Web Forms allowing
\r
29 /// a view of a DataTable for editing, filtering,
\r
30 /// navigation, searching, and sorting.
\r
33 [Editor ("Microsoft.VSDesigner.Data.Design.DataSourceEditor, " + Consts.AssemblyMicrosoft_VSDesigner,
\r
34 "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
\r
35 [DefaultEvent ("PositionChanged")]
\r
36 [DefaultProperty ("Table")]
\r
37 [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataViewDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
\r
38 public class DataView : MarshalByValueComponent, IBindingList, IList, ICollection, IEnumerable, ITypedList, ISupportInitialize
\r
40 internal DataTable dataTable = null;
\r
41 string rowFilter = String.Empty;
\r
42 IExpression rowFilterExpr;
\r
43 string sort = String.Empty;
\r
44 ListSortDirection [] sortOrder = null;
\r
45 PropertyDescriptor sortProperty = null;
\r
46 DataColumn [] sortColumns = null;
\r
47 internal DataViewRowState rowState;
\r
48 internal DataRowView[] rowCache = new DataRowView [0];
\r
50 // BeginInit() support
\r
51 bool isInitPhase = false;
\r
52 bool inEndInit = false;
\r
53 DataTable initTable;
\r
54 bool initApplyDefaultSort;
\r
56 string initRowFilter;
\r
57 DataViewRowState initRowState;
\r
59 // FIXME: what are the default values?
\r
60 bool allowNew = true;
\r
61 bool allowEdit = true;
\r
62 bool allowDelete = true;
\r
63 bool applyDefaultSort = false;
\r
64 bool isSorted = false;
\r
66 bool isOpen = false;
\r
68 bool useDefaultSort = true;
\r
71 internal DataRow _lastAdded = null;
\r
73 private DataViewManager dataViewManager = null;
\r
74 internal static ListChangedEventArgs ListResetEventArgs = new ListChangedEventArgs (ListChangedType.Reset,-1,-1);
\r
76 #region Constructors
\r
80 rowState = DataViewRowState.CurrentRows;
\r
84 public DataView (DataTable table)
\r
85 : this (table, (DataViewManager) null)
\r
89 internal DataView (DataTable table, DataViewManager manager)
\r
92 rowState = DataViewRowState.CurrentRows;
\r
93 dataViewManager = manager;
\r
97 public DataView (DataTable table, string rowFilter,
\r
98 string sort, DataViewRowState rowState)
\r
99 : this (table, null, rowFilter, sort, rowState)
\r
103 internal DataView (DataTable table, DataViewManager manager,
\r
104 string RowFilter, string Sort, DataViewRowState RowState)
\r
107 dataViewManager = manager;
\r
108 rowState = DataViewRowState.CurrentRows;
\r
109 this.RowFilter = RowFilter;
\r
111 rowState = RowState;
\r
114 #endregion // Constructors
\r
116 #region PublicProperties
\r
118 [DataCategory ("Data")]
\r
119 [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows deletes.")]
\r
120 [DefaultValue (true)]
\r
121 public bool AllowDelete {
\r
123 return allowDelete;
\r
126 allowDelete = value;
\r
130 [DataCategory ("Data")]
\r
131 [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows edits.")]
\r
132 [DefaultValue (true)]
\r
133 public bool AllowEdit {
\r
142 [DataCategory ("Data")]
\r
143 [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows new rows to be added.")]
\r
144 [DefaultValue (true)]
\r
145 public bool AllowNew {
\r
155 [DataCategory ("Data")]
\r
156 [DataSysDescription ("Indicates whether to use the default sort if the Sort property is not set.")]
\r
157 [DefaultValue (false)]
\r
158 [RefreshProperties (RefreshProperties.All)]
\r
159 public bool ApplyDefaultSort {
\r
160 get { return applyDefaultSort; }
\r
163 initApplyDefaultSort = value;
\r
166 if (applyDefaultSort == value)
\r
169 applyDefaultSort = value;
\r
170 if (applyDefaultSort == true &&
\r
171 (sort == null || sort == string.Empty))
\r
172 PopulateDefaultSort ();
\r
174 UpdateIndex (true);
\r
175 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
\r
179 // get the count of rows in the DataView after RowFilter
\r
180 // and RowStateFilter have been applied
\r
181 [Browsable (false)]
\r
182 [DataSysDescription ("Returns the number of items currently in this view.")]
\r
186 return rowCache.Length;
\r
190 [Browsable (false)]
\r
191 [DataSysDescription ("This returns a pointer to back to the DataViewManager that owns this DataSet (if any).")]
\r
192 public DataViewManager DataViewManager {
\r
195 return dataViewManager;
\r
200 // the compiler creates a DefaultMemeberAttribute from
\r
201 // this IndexerNameAttribute
\r
202 [System.Runtime.CompilerServices.IndexerName("Item")]
\r
203 public DataRowView this[int recordIndex] {
\r
206 if (recordIndex > rowCache.Length)
\r
207 throw new IndexOutOfRangeException ("There is no row at " +
\r
208 "position: " + recordIndex + ".");
\r
209 return rowCache [recordIndex];
\r
213 [DataCategory ("Data")]
\r
214 [DataSysDescription ("Indicates an expression used to filter the data returned by this DataView.")]
\r
215 [DefaultValue ("")]
\r
216 public virtual string RowFilter {
\r
217 get { return rowFilter; }
\r
221 value = String.Empty;
\r
223 initRowFilter = value;
\r
227 CultureInfo info = (Table != null) ? Table.Locale : CultureInfo.CurrentCulture;
\r
228 if (String.Compare(rowFilter, value, false, info) == 0)
\r
231 if (value == String.Empty)
\r
232 rowFilterExpr = null;
\r
234 Parser parser = new Parser ();
\r
235 rowFilterExpr = parser.Compile (value);
\r
239 UpdateIndex (true);
\r
243 [DataCategory ("Data")]
\r
244 [DataSysDescription ("Indicates the versions of data returned by this DataView.")]
\r
245 [DefaultValue (DataViewRowState.CurrentRows)]
\r
246 public DataViewRowState RowStateFilter {
\r
247 get { return rowState; }
\r
250 initRowState = value;
\r
254 if (value == rowState)
\r
259 UpdateIndex (true);
\r
260 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
\r
265 [DataCategory ("Data")]
\r
266 [DataSysDescription ("Indicates the order in which data is returned by this DataView.")]
\r
267 [DefaultValue ("")]
\r
268 public string Sort {
\r
270 if (useDefaultSort)
\r
271 return String.Empty;
\r
284 if ((value == null) || (value.Equals (String.Empty))) {
\r
285 /* if given value is null useDefaultSort */
\r
286 useDefaultSort = true;
\r
287 /* if ApplyDefault sort is true try appling it */
\r
288 if (ApplyDefaultSort == true)
\r
289 PopulateDefaultSort ();
\r
292 /* else donot useDefaultSort. set it as false */
\r
293 /* sort is set to value specified */
\r
294 useDefaultSort = false;
\r
296 //sortedColumns = SortableColumn.ParseSortString (dataTable, value, true);
\r
299 UpdateIndex (true);
\r
300 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
\r
305 [TypeConverter (typeof (DataTableTypeConverter))]
\r
306 [DataCategory ("Data")]
\r
307 [DataSysDescription ("Indicates the table this DataView uses to get data.")]
\r
308 [DefaultValue (null)]
\r
309 [RefreshProperties (RefreshProperties.All)]
\r
310 public DataTable Table {
\r
311 get { return dataTable; }
\r
318 if (value != null && value.TableName.Equals("")) {
\r
319 throw new DataException("Cannot bind to DataTable with no name.");
\r
322 if (dataTable != null) {
\r
323 UnregisterEventHandlers ();
\r
328 if (dataTable != null) {
\r
329 RegisterEventHandlers ();
\r
330 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged, 0, 0));
\r
333 rowFilterExpr = null;
\r
335 UpdateIndex (true);
\r
336 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
\r
342 #endregion // PublicProperties
\r
344 #region PublicMethods
\r
347 public virtual DataRowView AddNew()
\r
350 throw new DataException ("DataView is not open.");
\r
352 throw new DataException ("Cannot call AddNew on a DataView where AllowNew is false.");
\r
354 if (_lastAdded != null) {
\r
355 // FIXME : finish last added
\r
356 CompleteLastAdded(true);
\r
359 _lastAdded = dataTable.NewRow ();
\r
361 OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, Count - 1, -1));
\r
363 return this[Count - 1];
\r
366 internal void CompleteLastAdded(bool add)
\r
368 DataRow dr = _lastAdded;
\r
372 dataTable.Rows.Add(_lastAdded);
\r
373 //OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, Count - 1, -1));
\r
376 catch(Exception e) {
\r
382 _lastAdded.CancelEdit();
\r
385 OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, Count, -1));
\r
390 public void BeginInit()
\r
393 initApplyDefaultSort = ApplyDefaultSort;
\r
395 initRowFilter = RowFilter;
\r
396 initRowState = RowStateFilter;
\r
398 isInitPhase = true;
\r
402 public void CopyTo (Array array, int index)
\r
404 if (index + rowCache.Length > array.Length) {
\r
405 throw new IndexOutOfRangeException();
\r
409 for (; row < rowCache.Length && row < array.Length; row++) {
\r
410 array.SetValue (rowCache[row], index + row);
\r
414 public void Delete(int index)
\r
417 throw new DataException ("DataView is not open.");
\r
419 if (_lastAdded != null && index == Count) {
\r
420 CompleteLastAdded(false);
\r
425 throw new DataException ("Cannot delete on a DataSource where AllowDelete is false.");
\r
427 if (index > rowCache.Length)
\r
428 throw new IndexOutOfRangeException ("There is no row at " +
\r
429 "position: " + index + ".");
\r
430 DataRowView row = rowCache [index];
\r
436 public virtual bool Equals (DataView dv)
\r
438 throw new NotImplementedException ();
\r
443 public void EndInit()
\r
445 isInitPhase = false;
\r
450 ApplyDefaultSort = initApplyDefaultSort;
\r
452 RowFilter = initRowFilter;
\r
453 RowStateFilter = initRowState;
\r
457 UpdateIndex (true);
\r
461 public int Find(object key)
\r
463 object [] keys = new object[] { key };
\r
468 public int Find(object[] keys)
\r
470 if (sort == null || sort == string.Empty) {
\r
471 throw new ArgumentException ("Find finds a row based on a Sort order, and no Sort order is specified");
\r
474 if (Index == null) {
\r
480 index = Index.FindIndex(keys);
\r
482 catch(FormatException) {
\r
483 // suppress exception
\r
485 catch(InvalidCastException) {
\r
486 // suppress exception
\r
492 public DataRowView[] FindRows(object key)
\r
494 return FindRows(new object[] {key});
\r
498 public DataRowView[] FindRows(object[] keys)
\r
500 if (sort == null || sort == string.Empty) {
\r
501 throw new ArgumentException ("Find finds a row based on a Sort order, and no Sort order is specified");
\r
504 if (Index == null) {
\r
508 int[] indexes = Index.FindAllIndexes(keys);
\r
510 DataRowView[] rowViewArr = new DataRowView[indexes.Length];
\r
511 for (int r = 0; r < indexes.Length; r++) {
\r
512 rowViewArr[r] = rowCache[indexes[r]];
\r
517 public IEnumerator GetEnumerator()
\r
519 DataRowView[] dataRowViews = new DataRowView[Count];
\r
520 CopyTo(dataRowViews,0);
\r
521 return dataRowViews.GetEnumerator();
\r
524 #endregion // PublicMethods
\r
526 [DataCategory ("Data")]
\r
527 [DataSysDescription ("Indicates that the data returned by this DataView has somehow changed.")]
\r
528 public event ListChangedEventHandler ListChanged;
\r
530 [Browsable (false)]
\r
531 [DataSysDescription ("Indicates whether the view is open. ")]
\r
532 protected bool IsOpen {
\r
533 get { return isOpen; }
\r
536 internal Index Index
\r
543 if (_index != null) {
\r
544 _index.RemoveRef();
\r
545 Table.DropIndex(_index);
\r
550 if (_index != null) {
\r
556 protected void Close ()
\r
558 if (dataTable != null)
\r
559 UnregisterEventHandlers ();
\r
561 rowCache = new DataRowView [0];
\r
565 protected override void Dispose (bool disposing)
\r
570 base.Dispose (disposing);
\r
573 protected virtual void IndexListChanged (
\r
574 object sender, ListChangedEventArgs e)
\r
579 protected virtual void OnListChanged(ListChangedEventArgs e)
\r
581 // Yes, under MS.NET, when it is overriden, the
\r
582 // events are not fired (even if it is essential
\r
583 // to internal processing).
\r
585 if (ListChanged != null)
\r
586 ListChanged (this, e);
\r
591 internal void ChangedList(ListChangedType listChangedType, int newIndex,int oldIndex)
\r
593 ListChangedEventArgs e = new ListChangedEventArgs(listChangedType,newIndex,oldIndex);
\r
598 protected void Open()
\r
600 // I wonder if this comment is still valid, but keep
\r
601 // in the meantime.
\r
603 // FIXME: create the initial index cache to the DataTable, and
\r
604 // only refresh the index when the DataTable
\r
605 // has changes via column, row, or constraint
\r
606 // changed events. the index cache is generally
\r
607 // a DataViewRow array that points to the actual
\r
608 // DataRows in the this DataTable's DataRowCollection;
\r
609 // this index is really a cache that gets
\r
610 // created during Open(), gets Updated
\r
611 // when various properties of this view
\r
612 // changes, gets Updated when this DataTable's
\r
613 // row, column, or constraint collections have changed.
\r
614 // I'm not sure what else.
\r
615 // The data view will know one of the DataTable's
\r
616 // collections have changed via one of
\r
617 // its changed events.
\r
618 // Otherwise, if getting a/the DataRowView(s),
\r
619 // Count, or other properties, then just use the
\r
621 // dataTable.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged);
\r
623 UpdateIndex (true);
\r
624 if (dataTable != null) {
\r
625 RegisterEventHandlers();
\r
630 private void RegisterEventHandlers()
\r
632 //dataTable.ColumnChanging += new DataColumnChangeEventHandler(OnColumnChanging);
\r
633 dataTable.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged);
\r
634 dataTable.RowChanged += new DataRowChangeEventHandler(OnRowChanged);
\r
635 //dataTable.RowDeleting += new DataRowChangeEventHandler(OnRowDeleting);
\r
636 dataTable.RowDeleted += new DataRowChangeEventHandler(OnRowDeleted);
\r
637 dataTable.Columns.CollectionChanged += new CollectionChangeEventHandler(ColumnCollectionChanged);
\r
638 dataTable.Constraints.CollectionChanged += new CollectionChangeEventHandler(OnConstraintCollectionChanged);
\r
640 dataTable.Rows.ListChanged += new ListChangedEventHandler (OnRowCollectionChanged);
\r
643 private void OnRowCollectionChanged (object sender, ListChangedEventArgs args)
\r
645 if (args.ListChangedType == ListChangedType.Reset)
\r
646 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1 ));
\r
649 private void UnregisterEventHandlers()
\r
651 // dataTable.ColumnChanging -= new DataColumnChangeEventHandler(OnColumnChanging);
\r
652 dataTable.ColumnChanged -= new DataColumnChangeEventHandler(OnColumnChanged);
\r
653 dataTable.RowChanged -= new DataRowChangeEventHandler(OnRowChanged);
\r
654 // dataTable.RowDeleting -= new DataRowChangeEventHandler(OnRowDeleting);
\r
655 dataTable.RowDeleted -= new DataRowChangeEventHandler(OnRowDeleted);
\r
656 dataTable.Columns.CollectionChanged -= new CollectionChangeEventHandler(ColumnCollectionChanged);
\r
657 dataTable.Constraints.CollectionChanged -= new CollectionChangeEventHandler(OnConstraintCollectionChanged);
\r
659 dataTable.Rows.ListChanged -= new ListChangedEventHandler (OnRowCollectionChanged);
\r
662 // These index storing and rowView preservation must be done
\r
663 // before the actual row value is changed; thus we can't use
\r
664 // RowChanging which accepts "already modified" DataRow.
\r
666 private void OnColumnChanged(object sender, DataColumnChangeEventArgs args)
\r
668 //UpdateIndex(true);
\r
671 private void OnRowChanged(object sender, DataRowChangeEventArgs args)
\r
673 int oldIndex,newIndex;
\r
674 oldIndex = newIndex = -1;
\r
675 oldIndex = IndexOf (args.Row);
\r
676 UpdateIndex (true);
\r
677 newIndex = IndexOf (args.Row);
\r
680 if(args.Action == DataRowAction.Add)
\r
682 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, newIndex, -1));
\r
685 /* ItemChanged or ItemMoved */
\r
686 if (args.Action == DataRowAction.Change) {
\r
687 if (oldIndex == newIndex)
\r
688 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, newIndex, -1));
\r
690 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemMoved, newIndex, oldIndex));
\r
694 private void OnRowDeleted (object sender, DataRowChangeEventArgs args)
\r
698 newIndex = IndexOf (args.Row);
\r
699 UpdateIndex (true);
\r
700 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, newIndex, -1));
\r
703 protected virtual void ColumnCollectionChanged (object sender, CollectionChangeEventArgs args)
\r
705 // UpdateIndex() is not invoked here (even if the sort
\r
706 // column is being removed).
\r
708 /* PropertyDescriptor Add */
\r
709 if (args.Action == CollectionChangeAction.Add)
\r
710 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorAdded,0,0));
\r
711 /* PropertyDescriptor Removed */
\r
712 if (args.Action == CollectionChangeAction.Remove)
\r
713 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorDeleted,0,0));
\r
714 /* FIXME: PropertyDescriptor Changed ???*/
\r
715 if (args.Action == CollectionChangeAction.Refresh)
\r
716 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged,0,0));
\r
718 private void OnConstraintCollectionChanged(object sender, CollectionChangeEventArgs args)
\r
720 // The Sort variable is set to the UniqueConstraint column.
\r
721 // if ApplyDefault Sort is true and Sort is null or is not set Explicitly
\r
723 // FIXME: The interal cache may change as result of change in Constraint collection
\r
724 // one such scenerio is taken care.
\r
725 // There may be more. I dont know what else can be done.
\r
726 /* useDefaultSort is set to false when Sort is set explicitly */
\r
727 if (args.Action == CollectionChangeAction.Add && args.Element is UniqueConstraint) {
\r
728 if (ApplyDefaultSort == true && useDefaultSort == true)
\r
729 PopulateDefaultSort ((UniqueConstraint) args.Element);
\r
731 // UpdateIndex() is not invoked here.
\r
734 // internal use by Mono
\r
735 protected void Reset()
\r
737 // TODO: what really happens?
\r
739 rowCache = new DataRowView [0];
\r
741 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1 ));
\r
746 public DataTable ToTable ()
\r
748 throw new NotImplementedException ();
\r
752 public DataTable ToTable (bool isDistinct, string[] columnNames)
\r
754 throw new NotImplementedException ();
\r
757 protected void UpdateIndex() {
\r
758 UpdateIndex(false);
\r
761 // This is method is internal to
\r
762 // the Mono implementation of DataView; it
\r
763 // is not to be used from your code.
\r
765 // Update the DataRowView array which is an index cache
\r
766 // into the DataTable's DataRowCollection.
\r
768 // I assume this is what UpdateIndex is used for
\r
769 protected virtual void UpdateIndex(bool force)
\r
771 if (Table == null) {
\r
776 if (Index == null || force) {
\r
777 sortColumns = DataTable.ParseSortString(Table, Sort, out sortOrder, false);
\r
778 Index = dataTable.GetIndex(sortColumns,sortOrder,RowStateFilter,FilterExpression,true);
\r
781 Index.Key.RowStateFilter = RowStateFilter;
\r
785 int[] records = Index.GetAll();
\r
787 if (records != null) {
\r
788 InitDataRowViewArray(records,Index.Size);
\r
791 rowCache = new DataRowView[0];
\r
795 internal virtual IExpression FilterExpression
\r
798 return rowFilterExpr;
\r
802 private void InitDataRowViewArray(int[] records,int size)
\r
804 if (_lastAdded != null) {
\r
805 rowCache = new DataRowView[size + 1];
\r
808 rowCache = new DataRowView[size];
\r
811 for (int r = 0; r < size; r++) {
\r
812 rowCache[r] = new DataRowView (this, Table.RecordCache[records[r]],r);
\r
815 if(_lastAdded != null) {
\r
816 rowCache[size] = new DataRowView(this,_lastAdded,size);
\r
821 PropertyDescriptorCollection ITypedList.GetItemProperties (PropertyDescriptor[] listAccessors)
\r
823 // FIXME: use listAccessors somehow
\r
824 DataColumnPropertyDescriptor [] descriptors =
\r
825 new DataColumnPropertyDescriptor [dataTable.Columns.Count];
\r
827 DataColumnPropertyDescriptor descriptor;
\r
828 DataColumn dataColumn;
\r
829 for (int col = 0; col < dataTable.Columns.Count; col ++) {
\r
830 dataColumn = dataTable.Columns[col];
\r
831 descriptor = new DataColumnPropertyDescriptor(
\r
832 dataColumn.ColumnName, col, null);
\r
833 descriptor.SetComponentType (typeof (System.Data.DataRowView));
\r
834 descriptor.SetPropertyType (dataColumn.DataType);
\r
835 descriptor.SetReadOnly (dataColumn.ReadOnly);
\r
836 descriptors [col] = descriptor;
\r
838 return new PropertyDescriptorCollection (descriptors);
\r
842 string ITypedList.GetListName (PropertyDescriptor[] listAccessors)
\r
844 if (dataTable != null) {
\r
845 return dataTable.TableName;
\r
850 bool ICollection.IsSynchronized {
\r
857 object ICollection.SyncRoot {
\r
865 bool IList.IsFixedSize {
\r
872 bool IList.IsReadOnly {
\r
879 object IList.this[int recordIndex] {
\r
882 return this[recordIndex];
\r
887 throw new InvalidOperationException();
\r
891 int IList.Add (object value)
\r
893 throw new ArgumentException ("Cannot add external objects to this list.");
\r
896 void IList.Clear ()
\r
898 throw new ArgumentException ("Cannot clear this list.");
\r
901 bool IList.Contains (object value)
\r
903 DataRowView drv = value as DataRowView;
\r
907 return drv.DataView == this;
\r
910 int IList.IndexOf (object value)
\r
912 DataRowView drv = value as DataRowView;
\r
913 if (drv != null && drv.DataView == this) {
\r
920 void IList.Insert(int index,object value)
\r
922 throw new ArgumentException ("Cannot insert external objects to this list.");
\r
925 void IList.Remove(object value)
\r
927 DataRowView drv = value as DataRowView;
\r
928 if (drv != null && drv.DataView == this) {
\r
929 ((IList)this).RemoveAt(drv.Index);
\r
932 throw new ArgumentException ("Cannot remove external objects to this list.");
\r
935 void IList.RemoveAt(int index)
\r
940 #region IBindingList implementation
\r
943 void IBindingList.AddIndex (PropertyDescriptor property)
\r
945 throw new NotImplementedException ();
\r
948 object IBindingList.AddNew ()
\r
950 return this.AddNew ();
\r
953 void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction)
\r
955 if (! (property is DataColumnPropertyDescriptor))
\r
956 throw new ArgumentException ("Dataview accepts only DataColumnPropertyDescriptors", "property");
\r
957 sortProperty = property;
\r
958 string sort = String.Format ("[{0}]" , property.Name);
\r
959 if (direction == ListSortDirection.Descending)
\r
964 int IBindingList.Find (PropertyDescriptor property, object key)
\r
966 DataColumn dc = Table.Columns [property.Name];
\r
967 Index index = Table.FindIndex (new DataColumn [] { dc }, sortOrder, RowStateFilter, FilterExpression);
\r
969 index = new Index(new Key (Table, new DataColumn [] { dc }, sortOrder, RowStateFilter, FilterExpression));
\r
970 return index.FindIndex (new object [] {key});
\r
974 void IBindingList.RemoveIndex (PropertyDescriptor property)
\r
976 throw new NotImplementedException ();
\r
979 void IBindingList.RemoveSort ()
\r
981 sortProperty = null;
\r
982 this.Sort = String.Empty;
\r
985 bool IBindingList.AllowEdit {
\r
991 bool IBindingList.AllowNew {
\r
997 bool IBindingList.AllowRemove {
\r
1000 return AllowDelete;
\r
1004 bool IBindingList.IsSorted {
\r
1006 return Sort != null && Sort != String.Empty;
\r
1010 ListSortDirection IBindingList.SortDirection {
\r
1012 if (sortOrder != null && sortOrder.Length > 0)
\r
1013 return sortOrder [0];
\r
1014 return ListSortDirection.Ascending;
\r
1018 PropertyDescriptor IBindingList.SortProperty {
\r
1020 if (sortProperty == null && sortColumns != null && sortColumns.Length > 0) {
\r
1021 // return property from Sort String
\r
1022 PropertyDescriptorCollection properties = ( (ITypedList) this).GetItemProperties (null);
\r
1023 return properties.Find ( sortColumns [0].ColumnName, false);
\r
1025 return sortProperty;
\r
1029 bool IBindingList.SupportsChangeNotification {
\r
1035 bool IBindingList.SupportsSearching {
\r
1041 bool IBindingList.SupportsSorting {
\r
1047 #endregion // IBindingList implementation
\r
1048 private int IndexOf(DataRow dr)
\r
1050 for (int i=0; i < rowCache.Length; i++)
\r
1051 if (dr.Equals (rowCache [i].Row))
\r
1056 private void PopulateDefaultSort () {
\r
1058 foreach (Constraint c in dataTable.Constraints) {
\r
1059 if (c is UniqueConstraint) {
\r
1060 PopulateDefaultSort ((UniqueConstraint) c);
\r
1066 private void PopulateDefaultSort (UniqueConstraint uc) {
\r
1070 DataColumn[] columns = uc.Columns;
\r
1071 if (columns.Length == 0) {
\r
1072 sort = String.Empty;
\r
1076 StringBuilder builder = new StringBuilder();
\r
1077 builder.Append(columns[0].ColumnName);
\r
1078 for (int i = 1; i<columns.Length; i++) {
\r
1079 builder.Append(", ");
\r
1080 builder.Append(columns[i].ColumnName);
\r
1082 sort = builder.ToString();
\r
1085 internal DataView CreateChildView (DataRelation relation, int index)
\r
1087 if (relation == null || relation.ParentTable != Table) {
\r
1088 throw new ArgumentException("The relation is not parented to the table to which this DataView points.");
\r
1091 int record = GetRecord(index);
\r
1092 object[] keyValues = new object[relation.ParentColumns.Length];
\r
1093 for(int i=0; i < relation.ParentColumns.Length; i++)
\r
1094 keyValues [i] = relation.ParentColumns [i][record];
\r
1096 return new RelatedDataView(relation.ChildColumns,keyValues);
\r
1099 private int GetRecord(int index) {
\r
1100 if (index < 0 || index >= Count)
\r
1101 throw new IndexOutOfRangeException(String.Format("There is no row at position {0}.", index));
\r
1103 return(index == Index.Size) ?
\r
1104 _lastAdded.IndexFromVersion(DataRowVersion.Default) :
\r
1105 Index.IndexToRecord(index);
\r
1108 internal DataRowVersion GetRowVersion(int index) {
\r
1109 int record = GetRecord(index);
\r
1110 return Table.RecordCache[record].VersionFromIndex(record);
\r