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
34 [DefaultEvent ("PositionChanged")]
\r
35 [DefaultProperty ("Table")]
\r
36 [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataViewDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
\r
37 public class DataView : MarshalByValueComponent, IBindingList, IList, ICollection, IEnumerable, ITypedList, ISupportInitialize
\r
39 protected DataTable dataTable = null;
\r
40 string rowFilter = String.Empty;
\r
41 IExpression rowFilterExpr;
\r
42 string sort = String.Empty;
\r
43 protected DataViewRowState rowState;
\r
44 protected DataRowView[] rowCache = null;
\r
46 // BeginInit() support
\r
47 bool isInitPhase = false;
\r
48 bool inEndInit = false;
\r
49 DataTable initTable;
\r
50 bool initApplyDefaultSort;
\r
52 string initRowFilter;
\r
53 DataViewRowState initRowState;
\r
55 // FIXME: what are the default values?
\r
56 bool allowNew = true;
\r
57 bool allowEdit = true;
\r
58 bool allowDelete = true;
\r
59 bool applyDefaultSort = false;
\r
60 bool isSorted = false;
\r
62 bool isOpen = false;
\r
64 bool useDefaultSort = true;
\r
67 internal DataRow _lastAdded = null;
\r
69 private DataViewManager dataViewManager = null;
\r
70 internal static ListChangedEventArgs ListResetEventArgs = new ListChangedEventArgs (ListChangedType.Reset,-1,-1);
\r
72 #region Constructors
\r
76 rowState = DataViewRowState.CurrentRows;
\r
80 public DataView (DataTable table)
\r
81 : this (table, (DataViewManager) null)
\r
85 internal DataView (DataTable table, DataViewManager manager)
\r
88 rowState = DataViewRowState.CurrentRows;
\r
89 dataViewManager = manager;
\r
93 public DataView (DataTable table, string rowFilter,
\r
94 string sort, DataViewRowState rowState)
\r
95 : this (table, null, rowFilter, sort, rowState)
\r
99 internal DataView (DataTable table, DataViewManager manager,
\r
100 string RowFilter, string Sort, DataViewRowState RowState)
\r
103 dataViewManager = manager;
\r
104 rowState = DataViewRowState.CurrentRows;
\r
105 this.RowFilter = RowFilter;
\r
107 rowState = RowState;
\r
110 #endregion // Constructors
\r
112 #region PublicProperties
\r
114 [DataCategory ("Data")]
\r
115 [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows deletes.")]
\r
116 [DefaultValue (true)]
\r
117 public bool AllowDelete {
\r
119 return allowDelete;
\r
122 allowDelete = value;
\r
126 [DataCategory ("Data")]
\r
127 [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows edits.")]
\r
128 [DefaultValue (true)]
\r
129 public bool AllowEdit {
\r
138 [DataCategory ("Data")]
\r
139 [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows new rows to be added.")]
\r
140 [DefaultValue (true)]
\r
141 public bool AllowNew {
\r
151 [DataCategory ("Data")]
\r
152 [DataSysDescription ("Indicates whether to use the default sort if the Sort property is not set.")]
\r
153 [DefaultValue (false)]
\r
154 [RefreshProperties (RefreshProperties.All)]
\r
155 public bool ApplyDefaultSort {
\r
156 get { return applyDefaultSort; }
\r
159 initApplyDefaultSort = value;
\r
162 if (applyDefaultSort == value)
\r
165 applyDefaultSort = value;
\r
166 if (applyDefaultSort == true &&
\r
167 (sort == null || sort == string.Empty))
\r
168 PopulateDefaultSort ();
\r
170 UpdateIndex (true);
\r
173 // get the count of rows in the DataView after RowFilter
\r
174 // and RowStateFilter have been applied
\r
175 [Browsable (false)]
\r
176 [DataSysDescription ("Returns the number of items currently in this view.")]
\r
180 return rowCache.Length;
\r
184 [Browsable (false)]
\r
185 [DataSysDescription ("This returns a pointer to back to the DataViewManager that owns this DataSet (if any).")]
\r
186 public DataViewManager DataViewManager {
\r
189 return dataViewManager;
\r
194 // the compiler creates a DefaultMemeberAttribute from
\r
195 // this IndexerNameAttribute
\r
196 [System.Runtime.CompilerServices.IndexerName("Item")]
\r
197 public DataRowView this[int recordIndex] {
\r
200 return rowCache [recordIndex];
\r
204 [DataCategory ("Data")]
\r
205 [DataSysDescription ("Indicates an expression used to filter the data returned by this DataView.")]
\r
206 [DefaultValue ("")]
\r
207 public virtual string RowFilter {
\r
208 get { return rowFilter; }
\r
212 value = String.Empty;
\r
214 initRowFilter = value;
\r
218 CultureInfo info = (Table != null) ? Table.Locale : CultureInfo.CurrentCulture;
\r
219 if (String.Compare(rowFilter, value, false, info) == 0)
\r
222 if (value == String.Empty)
\r
223 rowFilterExpr = null;
\r
225 Parser parser = new Parser ();
\r
226 rowFilterExpr = parser.Compile (value);
\r
230 UpdateIndex (true);
\r
234 [DataCategory ("Data")]
\r
235 [DataSysDescription ("Indicates the versions of data returned by this DataView.")]
\r
236 [DefaultValue (DataViewRowState.CurrentRows)]
\r
237 public DataViewRowState RowStateFilter {
\r
238 get { return rowState; }
\r
241 initRowState = value;
\r
245 if (value == rowState)
\r
250 UpdateIndex (true);
\r
254 [DataCategory ("Data")]
\r
255 [DataSysDescription ("Indicates the order in which data is returned by this DataView.")]
\r
256 [DefaultValue ("")]
\r
257 public string Sort {
\r
258 get { return sort; }
\r
267 if (value == null) {
\r
268 /* if given value is null useDefaultSort */
\r
269 useDefaultSort = true;
\r
270 /* if ApplyDefault sort is true try appling it */
\r
271 if (ApplyDefaultSort == true)
\r
272 PopulateDefaultSort ();
\r
275 /* else donot useDefaultSort. set it as false */
\r
276 /* sort is set to value specified */
\r
277 useDefaultSort = false;
\r
279 //sortedColumns = SortableColumn.ParseSortString (dataTable, value, true);
\r
282 UpdateIndex (true);
\r
286 [DataCategory ("Data")]
\r
287 [DataSysDescription ("Indicates the table this DataView uses to get data.")]
\r
288 [DefaultValue (null)]
\r
289 [RefreshProperties (RefreshProperties.All)]
\r
290 public DataTable Table {
\r
291 get { return dataTable; }
\r
298 if (value != null && value.TableName.Equals("")) {
\r
299 throw new DataException("Cannot bind to DataTable with no name.");
\r
302 if (dataTable != null) {
\r
303 UnregisterEventHandlers ();
\r
308 if (dataTable != null) {
\r
309 RegisterEventHandlers ();
\r
310 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged, 0, 0));
\r
313 rowFilterExpr = null;
\r
315 UpdateIndex (true);
\r
320 #endregion // PublicProperties
\r
322 #region PublicMethods
\r
325 public virtual DataRowView AddNew()
\r
328 throw new DataException ("DataView is not open.");
\r
330 throw new DataException ("Cannot call AddNew on a DataView where AllowNew is false.");
\r
332 if (_lastAdded != null) {
\r
333 // FIXME : finish last added
\r
334 CompleteLastAdded(true);
\r
337 _lastAdded = dataTable.NewRow ();
\r
339 OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, Count - 1, -1));
\r
341 return this[Count - 1];
\r
344 internal void CompleteLastAdded(bool add)
\r
346 DataRow dr = _lastAdded;
\r
350 dataTable.Rows.Add(_lastAdded);
\r
351 OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, Count - 1, -1));
\r
354 catch(Exception e) {
\r
360 _lastAdded.CancelEdit();
\r
362 OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, Count - 1));
\r
367 public void BeginInit()
\r
370 initApplyDefaultSort = ApplyDefaultSort;
\r
372 initRowFilter = RowFilter;
\r
373 initRowState = RowStateFilter;
\r
375 isInitPhase = true;
\r
379 public void CopyTo (Array array, int index)
\r
381 if (index + rowCache.Length > array.Length) {
\r
382 throw new IndexOutOfRangeException();
\r
386 for (; row < rowCache.Length && row < array.Length; row++) {
\r
387 array.SetValue (rowCache[row], index + row);
\r
391 public void Delete(int index)
\r
394 throw new DataException ("DataView is not open.");
\r
396 if (_lastAdded != null && index == Count) {
\r
397 CompleteLastAdded(false);
\r
402 throw new DataException ("Cannot delete on a DataSource where AllowDelete is false.");
\r
404 if (index > rowCache.Length)
\r
405 throw new IndexOutOfRangeException ("There is no row at " +
\r
406 "position: " + index + ".");
\r
407 DataRowView row = rowCache [index];
\r
413 public virtual bool Equals (DataView dv)
\r
415 throw new NotImplementedException ();
\r
420 public void EndInit()
\r
422 isInitPhase = false;
\r
427 ApplyDefaultSort = initApplyDefaultSort;
\r
429 RowFilter = initRowFilter;
\r
430 RowStateFilter = initRowState;
\r
434 UpdateIndex (true);
\r
438 public int Find(object key)
\r
440 object [] keys = new object[] { key };
\r
445 public int Find(object[] keys)
\r
447 if (sort == null || sort == string.Empty) {
\r
448 throw new ArgumentException ("Find finds a row based on a Sort order, and no Sort order is specified");
\r
451 if (Index == null) {
\r
457 index = Index.FindIndex(keys);
\r
459 catch(FormatException) {
\r
460 // suppress exception
\r
462 catch(InvalidCastException) {
\r
463 // suppress exception
\r
469 public DataRowView[] FindRows(object key)
\r
471 return FindRows(new object[] {key});
\r
475 public DataRowView[] FindRows(object[] keys)
\r
477 if (sort == null || sort == string.Empty) {
\r
478 throw new ArgumentException ("Find finds a row based on a Sort order, and no Sort order is specified");
\r
481 if (Index == null) {
\r
485 int[] indexes = Index.FindAllIndexes(keys);
\r
487 DataRowView[] rowViewArr = new DataRowView[indexes.Length];
\r
488 for (int r = 0; r < indexes.Length; r++) {
\r
489 rowViewArr[r] = rowCache[indexes[r]];
\r
494 public IEnumerator GetEnumerator()
\r
496 DataRowView[] dataRowViews = new DataRowView[Count];
\r
497 CopyTo(dataRowViews,0);
\r
498 return dataRowViews.GetEnumerator();
\r
501 #endregion // PublicMethods
\r
503 [DataCategory ("Data")]
\r
504 [DataSysDescription ("Indicates the data returned by this DataView has somehow changed.")]
\r
505 public event ListChangedEventHandler ListChanged;
\r
507 [Browsable (false)]
\r
508 [DataSysDescription ("Indicates whether the view is open.")]
\r
509 protected bool IsOpen {
\r
510 get { return isOpen; }
\r
513 internal Index Index
\r
520 if (_index != null) {
\r
521 _index.RemoveRef();
\r
522 Table.DropIndex(_index);
\r
527 if (_index != null) {
\r
533 protected void Close ()
\r
535 if (dataTable != null)
\r
536 UnregisterEventHandlers ();
\r
542 protected override void Dispose (bool disposing)
\r
547 base.Dispose (disposing);
\r
550 protected virtual void IndexListChanged (
\r
551 object sender, ListChangedEventArgs e)
\r
556 protected virtual void OnListChanged(ListChangedEventArgs e)
\r
558 // Yes, under MS.NET, when it is overriden, the
\r
559 // events are not fired (even if it is essential
\r
560 // to internal processing).
\r
562 if (ListChanged != null)
\r
563 ListChanged (this, e);
\r
568 internal void ChangedList(ListChangedType listChangedType, int newIndex,int oldIndex)
\r
570 ListChangedEventArgs e = new ListChangedEventArgs(listChangedType,newIndex,oldIndex);
\r
575 protected void Open()
\r
577 // I wonder if this comment is still valid, but keep
\r
578 // in the meantime.
\r
580 // FIXME: create the initial index cache to the DataTable, and
\r
581 // only refresh the index when the DataTable
\r
582 // has changes via column, row, or constraint
\r
583 // changed events. the index cache is generally
\r
584 // a DataViewRow array that points to the actual
\r
585 // DataRows in the this DataTable's DataRowCollection;
\r
586 // this index is really a cache that gets
\r
587 // created during Open(), gets Updated
\r
588 // when various properties of this view
\r
589 // changes, gets Updated when this DataTable's
\r
590 // row, column, or constraint collections have changed.
\r
591 // I'm not sure what else.
\r
592 // The data view will know one of the DataTable's
\r
593 // collections have changed via one of
\r
594 // its changed events.
\r
595 // Otherwise, if getting a/the DataRowView(s),
\r
596 // Count, or other properties, then just use the
\r
598 // dataTable.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged);
\r
600 UpdateIndex (true);
\r
601 if (dataTable != null) {
\r
602 RegisterEventHandlers();
\r
607 private void RegisterEventHandlers()
\r
609 //dataTable.ColumnChanging += new DataColumnChangeEventHandler(OnColumnChanging);
\r
610 dataTable.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged);
\r
611 dataTable.RowChanged += new DataRowChangeEventHandler(OnRowChanged);
\r
612 //dataTable.RowDeleting += new DataRowChangeEventHandler(OnRowDeleting);
\r
613 dataTable.RowDeleted += new DataRowChangeEventHandler(OnRowDeleted);
\r
614 dataTable.Columns.CollectionChanged += new CollectionChangeEventHandler(ColumnCollectionChanged);
\r
615 dataTable.Constraints.CollectionChanged += new CollectionChangeEventHandler(OnConstraintCollectionChanged);
\r
618 private void UnregisterEventHandlers()
\r
620 // dataTable.ColumnChanging -= new DataColumnChangeEventHandler(OnColumnChanging);
\r
621 dataTable.ColumnChanged -= new DataColumnChangeEventHandler(OnColumnChanged);
\r
622 dataTable.RowChanged -= new DataRowChangeEventHandler(OnRowChanged);
\r
623 // dataTable.RowDeleting -= new DataRowChangeEventHandler(OnRowDeleting);
\r
624 dataTable.RowDeleted -= new DataRowChangeEventHandler(OnRowDeleted);
\r
625 dataTable.Columns.CollectionChanged -= new CollectionChangeEventHandler(ColumnCollectionChanged);
\r
626 dataTable.Constraints.CollectionChanged -= new CollectionChangeEventHandler(OnConstraintCollectionChanged);
\r
629 // These index storing and rowView preservation must be done
\r
630 // before the actual row value is changed; thus we can't use
\r
631 // RowChanging which accepts "already modified" DataRow.
\r
633 private void OnColumnChanged(object sender, DataColumnChangeEventArgs args)
\r
635 //UpdateIndex(true);
\r
638 private void OnRowChanged(object sender, DataRowChangeEventArgs args)
\r
640 int oldIndex,newIndex;
\r
641 oldIndex = newIndex = -1;
\r
642 oldIndex = IndexOf (args.Row);
\r
643 UpdateIndex (true);
\r
644 newIndex = IndexOf (args.Row);
\r
647 if(args.Action == DataRowAction.Add)
\r
649 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, newIndex, -1));
\r
652 /* ItemChanged or ItemMoved */
\r
653 if (args.Action == DataRowAction.Change) {
\r
654 if (oldIndex == newIndex)
\r
655 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, newIndex, -1));
\r
657 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemMoved, newIndex, oldIndex));
\r
661 private void OnRowDeleted (object sender, DataRowChangeEventArgs args)
\r
665 newIndex = IndexOf (args.Row);
\r
666 UpdateIndex (true);
\r
667 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, newIndex, -1));
\r
670 protected virtual void ColumnCollectionChanged (object sender, CollectionChangeEventArgs args)
\r
672 // UpdateIndex() is not invoked here (even if the sort
\r
673 // column is being removed).
\r
675 /* PropertyDescriptor Add */
\r
676 if (args.Action == CollectionChangeAction.Add)
\r
677 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorAdded,0,0));
\r
678 /* PropertyDescriptor Removed */
\r
679 if (args.Action == CollectionChangeAction.Remove)
\r
680 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorDeleted,0,0));
\r
681 /* FIXME: PropertyDescriptor Changed ???*/
\r
682 if (args.Action == CollectionChangeAction.Refresh)
\r
683 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged,0,0));
\r
685 private void OnConstraintCollectionChanged(object sender, CollectionChangeEventArgs args)
\r
687 // The Sort variable is set to the UniqueConstraint column.
\r
688 // if ApplyDefault Sort is true and Sort is null or is not set Explicitly
\r
690 // FIXME: The interal cache may change as result of change in Constraint collection
\r
691 // one such scenerio is taken care.
\r
692 // There may be more. I dont know what else can be done.
\r
693 /* useDefaultSort is set to false when Sort is set explicitly */
\r
694 if (args.Action == CollectionChangeAction.Add && args.Element is UniqueConstraint) {
\r
695 if (ApplyDefaultSort == true && useDefaultSort == true)
\r
696 PopulateDefaultSort ((UniqueConstraint) args.Element);
\r
698 // UpdateIndex() is not invoked here.
\r
701 // internal use by Mono
\r
702 protected void Reset()
\r
704 // TODO: what really happens?
\r
708 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 ));
\r
713 public DataTable ToTable ()
\r
715 throw new NotImplementedException ();
\r
719 public DataTable ToTable (bool isDistinct, string[] columnNames)
\r
721 throw new NotImplementedException ();
\r
724 protected void UpdateIndex() {
\r
725 UpdateIndex(false);
\r
728 // This is method is internal to
\r
729 // the Mono implementation of DataView; it
\r
730 // is not to be used from your code.
\r
732 // Update the DataRowView array which is an index cache
\r
733 // into the DataTable's DataRowCollection.
\r
735 // I assume this is what UpdateIndex is used for
\r
736 protected virtual void UpdateIndex(bool force)
\r
738 if (Table == null) {
\r
743 if (Index == null || force) {
\r
744 ListSortDirection[] sortOrder = null;
\r
745 DataColumn[] columns = DataTable.ParseSortString(Table, Sort, out sortOrder, false);
\r
746 Index = dataTable.GetIndex(columns,sortOrder,RowStateFilter,FilterExpression,true);
\r
749 Index.Key.RowStateFilter = RowStateFilter;
\r
753 int[] records = Index.GetAll();
\r
755 if (records != null) {
\r
756 InitDataRowViewArray(records,Index.Size);
\r
759 rowCache = new DataRowView[0];
\r
762 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));
\r
765 internal virtual IExpression FilterExpression
\r
768 return rowFilterExpr;
\r
772 private void InitDataRowViewArray(int[] records,int size)
\r
774 if (_lastAdded != null) {
\r
775 rowCache = new DataRowView[size + 1];
\r
778 rowCache = new DataRowView[size];
\r
781 for (int r = 0; r < size; r++) {
\r
782 rowCache[r] = new DataRowView (this, Table.RecordCache[records[r]],r);
\r
785 if(_lastAdded != null) {
\r
786 rowCache[size] = new DataRowView(this,_lastAdded,size);
\r
791 PropertyDescriptorCollection ITypedList.GetItemProperties (PropertyDescriptor[] listAccessors)
\r
793 // FIXME: use listAccessors somehow
\r
794 DataColumnPropertyDescriptor [] descriptors =
\r
795 new DataColumnPropertyDescriptor [dataTable.Columns.Count];
\r
797 DataColumnPropertyDescriptor descriptor;
\r
798 DataColumn dataColumn;
\r
799 for (int col = 0; col < dataTable.Columns.Count; col ++) {
\r
800 dataColumn = dataTable.Columns[col];
\r
801 descriptor = new DataColumnPropertyDescriptor(
\r
802 dataColumn.ColumnName, col, null);
\r
803 descriptor.SetComponentType (typeof (System.Data.DataRowView));
\r
804 descriptor.SetPropertyType (dataColumn.DataType);
\r
805 descriptor.SetReadOnly (dataColumn.ReadOnly);
\r
806 descriptors [col] = descriptor;
\r
808 return new PropertyDescriptorCollection (descriptors);
\r
812 string ITypedList.GetListName (PropertyDescriptor[] listAccessors)
\r
817 bool ICollection.IsSynchronized {
\r
824 object ICollection.SyncRoot {
\r
832 bool IList.IsFixedSize {
\r
839 bool IList.IsReadOnly {
\r
846 object IList.this[int recordIndex] {
\r
849 return this[recordIndex];
\r
854 throw new InvalidOperationException();
\r
858 int IList.Add (object value)
\r
860 throw new ArgumentException ("Cannot add external objects to this list.");
\r
863 void IList.Clear ()
\r
865 throw new ArgumentException ("Cannot clear this list.");
\r
868 bool IList.Contains (object value)
\r
870 DataRowView drv = value as DataRowView;
\r
874 return drv.DataView == this;
\r
877 int IList.IndexOf (object value)
\r
879 DataRowView drv = value as DataRowView;
\r
880 if (drv != null && drv.DataView == this) {
\r
887 void IList.Insert(int index,object value)
\r
889 throw new ArgumentException ("Cannot insert external objects to this list.");
\r
892 void IList.Remove(object value)
\r
894 DataRowView drv = value as DataRowView;
\r
895 if (drv != null && drv.DataView == this) {
\r
896 ((IList)this).RemoveAt(drv.Index);
\r
899 throw new ArgumentException ("Cannot remove external objects to this list.");
\r
902 void IList.RemoveAt(int index)
\r
907 #region IBindingList implementation
\r
910 void IBindingList.AddIndex (PropertyDescriptor property)
\r
912 throw new NotImplementedException ();
\r
916 object IBindingList.AddNew ()
\r
918 return this.AddNew ();
\r
922 void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction)
\r
924 throw new NotImplementedException ();
\r
928 int IBindingList.Find (PropertyDescriptor property, object key)
\r
930 throw new NotImplementedException ();
\r
934 void IBindingList.RemoveIndex (PropertyDescriptor property)
\r
936 throw new NotImplementedException ();
\r
940 void IBindingList.RemoveSort ()
\r
942 throw new NotImplementedException ();
\r
945 bool IBindingList.AllowEdit {
\r
952 bool IBindingList.AllowNew {
\r
959 bool IBindingList.AllowRemove {
\r
962 return AllowDelete;
\r
966 bool IBindingList.IsSorted {
\r
973 ListSortDirection IBindingList.SortDirection {
\r
977 return ListSortDirection.Ascending;
\r
981 PropertyDescriptor IBindingList.SortProperty {
\r
989 bool IBindingList.SupportsChangeNotification {
\r
996 bool IBindingList.SupportsSearching {
\r
1003 bool IBindingList.SupportsSorting {
\r
1010 #endregion // IBindingList implementation
\r
1011 private int IndexOf(DataRow dr)
\r
1013 for (int i=0; i < rowCache.Length; i++)
\r
1014 if (dr.Equals (rowCache [i].Row))
\r
1019 private void PopulateDefaultSort () {
\r
1021 foreach (Constraint c in dataTable.Constraints) {
\r
1022 if (c is UniqueConstraint) {
\r
1023 PopulateDefaultSort ((UniqueConstraint) c);
\r
1029 private void PopulateDefaultSort (UniqueConstraint uc) {
\r
1033 DataColumn[] columns = uc.Columns;
\r
1034 if (columns.Length == 0) {
\r
1035 sort = String.Empty;
\r
1039 StringBuilder builder = new StringBuilder();
\r
1040 builder.Append(columns[0].ColumnName);
\r
1041 for (int i = 1; i<columns.Length; i++) {
\r
1042 builder.Append(", ");
\r
1043 builder.Append(columns[i].ColumnName);
\r
1045 sort = builder.ToString();
\r
1048 internal DataView CreateChildView (DataRelation relation, int index)
\r
1050 if (relation == null || relation.ParentTable != Table) {
\r
1051 throw new ArgumentException("The relation is not parented to the table to which this DataView points.");
\r
1054 int record = GetRecord(index);
\r
1055 object[] keyValues = new object[relation.ParentColumns.Length];
\r
1056 for(int i=0; i < relation.ParentColumns.Length; i++)
\r
1057 keyValues [i] = relation.ParentColumns [i][record];
\r
1059 return new RelatedDataView(relation.ChildColumns,keyValues);
\r
1062 private int GetRecord(int index) {
\r
1063 if (index < 0 || index >= Count)
\r
1064 throw new IndexOutOfRangeException(String.Format("There is no row at position {0}.", index));
\r
1066 return(index == Index.Size) ?
\r
1067 _lastAdded.IndexFromVersion(DataRowVersion.Default) :
\r
1068 Index.IndexToRecord(index);
\r
1071 internal DataRowVersion GetRowVersion(int index) {
\r
1072 int record = GetRecord(index);
\r
1073 return Table.RecordCache[record].VersionFromIndex(record);
\r