-//
-// System.Data.DataView.cs
-//
-// Author:
-// Daniel Morgan <danmorg@sc.rr.com>
-// Tim Coleman (tim@timcoleman.com)
-//
-// Copyright (C) Daniel Morgan, 2002, 2003
-// (C) Ximian, Inc 2002
-// Copyright (C) Tim Coleman, 2002-2003
-//
-
-//
-// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
-//
-// Permission is hereby granted, free of charge, to any person obtaining
-// a copy of this software and associated documentation files (the
-// "Software"), to deal in the Software without restriction, including
-// without limitation the rights to use, copy, modify, merge, publish,
-// distribute, sublicense, and/or sell copies of the Software, and to
-// permit persons to whom the Software is furnished to do so, subject to
-// the following conditions:
-//
-// The above copyright notice and this permission notice shall be
-// included in all copies or substantial portions of the Software.
-//
-// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-//
-
-using System;
-using System.Collections;
-using System.ComponentModel;
-using System.Reflection;
-
-namespace System.Data
-{
- /// <summary>
- /// A DataView is used in the binding of data between
- /// a DataTable and Windows Forms or Web Forms allowing
- /// a view of a DataTable for editing, filtering,
- /// navigation, searching, and sorting.
- /// </summary>
- //[Designer]
- [Editor]
- [DefaultEvent ("PositionChanged")]
- [DefaultProperty ("Table")]
- [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataViewDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]
- public class DataView : MarshalByValueComponent, IBindingList, IList, ICollection, IEnumerable, ITypedList, ISupportInitialize
- {
- DataTable dataTable = null;
- string rowFilter = "";
- string sort = "";
- DataViewRowState rowState;
- DataRowView[] rowCache = null;
-
- // FIXME: what are the default values?
- bool allowNew = true;
- bool allowEdit = true;
- bool allowDelete = true;
- bool applyDefaultSort = false;
- bool isSorted = false;
-
- bool isOpen = false;
-
- bool bInit = false;
-
- internal DataViewManager dataViewManager = null;
-
- public DataView ()
- {
- dataTable = new DataTable ();
- rowState = DataViewRowState.CurrentRows;
- Open ();
- }
-
- public DataView (DataTable table)
- {
- dataTable = table;
- rowState = DataViewRowState.CurrentRows;
- Open ();
- }
-
- public DataView (DataTable table, string RowFilter,
- string Sort, DataViewRowState RowState)
- {
- dataTable = table;
- rowState = DataViewRowState.CurrentRows;
- rowFilter = RowFilter;
- sort = Sort;
- rowState = RowState;
- Open();
- }
-
- [DataCategory ("Data")]
- [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows deletes.")]
- [DefaultValue (true)]
- public bool AllowDelete {
- get {
- return allowDelete;
- }
- set {
- allowDelete = value;
- }
- }
-
- [DataCategory ("Data")]
- [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows edits.")]
- [DefaultValue (true)]
- public bool AllowEdit {
- get {
- return allowEdit;
- }
- set {
- allowEdit = value;
- }
- }
-
- [DataCategory ("Data")]
- [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows new rows to be added.")]
- [DefaultValue (true)]
- public bool AllowNew {
- get {
- return allowNew;
- }
-
- set {
- allowNew = value;
- }
- }
-
- [DataCategory ("Data")]
- [DataSysDescription ("Indicates whether to use the default sort if the Sort property is not set.")]
- [DefaultValue (false)]
- [RefreshProperties (RefreshProperties.All)]
- public bool ApplyDefaultSort {
- [MonoTODO]
- get {
- return applyDefaultSort;
- }
-
- [MonoTODO]
- set {
- applyDefaultSort = value;
- // FIXME: update the index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events
- UpdateIndex ();
- }
- }
-
- // get the count of rows in the DataView after RowFilter
- // and RowStateFilter have been applied
- [Browsable (false)]
- [DataSysDescription ("Returns the number of items currently in this view.")]
- public int Count {
- [MonoTODO]
- get {
- // FIXME: remove this line once collection change
- // events from the DataTable are handled
- UpdateIndex ();
-
- return rowCache.Length;;
- }
- }
-
- [Browsable (false)]
- [DataSysDescription ("This returns a pointer to back to the DataViewManager that owns this DataSet (if any).")]
- public DataViewManager DataViewManager {
- [MonoTODO]
- get {
- return dataViewManager;
- }
- }
-
- // Item indexer
- // the compiler creates a DefaultMemeberAttribute from
- // this IndexerNameAttribute
- [System.Runtime.CompilerServices.IndexerName("Item")]
- public DataRowView this[int recordIndex] {
- [MonoTODO]
- get {
- // FIXME: use index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events
- // Remove this line once changed events are handled
- UpdateIndex ();
-
- return rowCache[recordIndex];
- }
- }
-
- [DataCategory ("Data")]
- [DataSysDescription ("Indicates an expression used to filter the data returned by this DataView.")]
- [DefaultValue ("")]
- public virtual string RowFilter {
- [MonoTODO]
- get {
- return rowFilter;
- }
-
- [MonoTODO]
- set {
- rowFilter = value;
- // FIXME: update the index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events
- UpdateIndex ();
- }
- }
-
- [DataCategory ("Data")]
- [DataSysDescription ("Indicates the versions of data returned by this DataView.")]
- [DefaultValue (DataViewRowState.CurrentRows)]
- public DataViewRowState RowStateFilter {
- [MonoTODO]
- get {
- return rowState;
- }
-
- [MonoTODO]
- set {
- rowState = value;
- // FIXME: update the index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events
- UpdateIndex ();
- }
- }
-
- [DataCategory ("Data")]
- [DataSysDescription ("Indicates the order in which data is returned by this DataView.")]
- [DefaultValue ("")]
- public string Sort {
- [MonoTODO]
- get {
- return sort;
- }
-
- [MonoTODO]
- set {
- sort = value;
- // FIXME: update the index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events
- UpdateIndex ();
- OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));
- }
- }
-
- [DataCategory ("Data")]
- [DataSysDescription ("Indicates the table this DataView uses to get data.")]
- [DefaultValue (null)]
- [RefreshProperties (RefreshProperties.All)]
- [TypeConverter (typeof(DataTableTypeConverter))]
- public DataTable Table {
- [MonoTODO]
- get {
- return dataTable;
- }
-
- [MonoTODO]
- set {
- dataTable = value;
- // FIXME: update the index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events
- UpdateIndex ();
- }
- }
-
- [MonoTODO]
- public virtual DataRowView AddNew()
- {
- if (!IsOpen)
- throw new DataException ("DataView is not open.");
- if (!AllowNew)
- throw new DataException ("Cannot call AddNew on a DataView where AllowNew is false.");
-
- DataRow row = dataTable.NewRow ();
- DataRowView rowView = new DataRowView (this, row, true);
-
- dataTable.Rows.Add (row);
-
- UpdateIndex ();
- OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, rowCache.Length - 1,-1));
- return rowView;
- }
-
- [MonoTODO]
- public void BeginInit()
- {
- bInit = true;
- // FIXME:
- }
-
- [MonoTODO]
- public void CopyTo (Array array, int index)
- {
- // FIXME: use index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events
- UpdateIndex ();
-
- int row = 0;
- for (; row < rowCache.Length && row < array.Length; row++) {
- array.SetValue (rowCache[row], index + row);
- }
- if (row < array.Length) {
- for (int r = 0; r < array.Length; r++) {
- array.SetValue (null, index + r);
- }
- }
- }
-
- public void Delete(int index)
- {
- if (!IsOpen)
- throw new DataException ("DataView is not open.");
- if (!AllowDelete)
- throw new DataException ("Cannot delete on a DataSource where AllowDelete is false.");
-
- UpdateIndex ();
-
- if (index > rowCache.Length)
- throw new IndexOutOfRangeException ("There is no row at " +
- "position: " + index + ".");
-
- DataRowView row = rowCache [index];
- row.Row.Delete ();
-
- OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, index));
- }
-
-#if NET_2_0
- [MonoTODO]
- public virtual bool Equals (DataView dv)
- {
- throw new NotImplementedException ();
- }
-#endif
-
- [MonoTODO]
- public void EndInit()
- {
- bInit = false;
- // FIXME:
- }
-
- [MonoTODO]
- public int Find(object key)
- {
- // FIXME: use index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events
-
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- public int Find(object[] key)
- {
- // FIXME: use an index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events
-
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- public DataRowView[] FindRows(object key)
- {
- // FIXME: use an index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events
-
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- public DataRowView[] FindRows(object[] key)
- {
- // FIXME: use an index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events
-
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- public IEnumerator GetEnumerator()
- {
- // FIXME: use an index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events
- UpdateIndex ();
-
- return new DataViewEnumerator (rowCache);
- }
-
- [MonoTODO]
- [DataCategory ("Data")]
- [DataSysDescription ("Indicates the data returned by this DataView has somehow changed.")]
- public event ListChangedEventHandler ListChanged;
-
- [Browsable (false)]
- [DataSysDescription ("DataViewIsOpenDescr")]
- protected bool IsOpen {
- [MonoTODO]
- get {
- return isOpen;
- }
- }
-
- [MonoTODO]
- protected void Close()
- {
- // FIXME:
- isOpen = false;
- }
-
- [MonoTODO]
- protected virtual void ColumnCollectionChanged (object sender,
- CollectionChangeEventArgs e)
- {
- throw new NotImplementedException ();
- }
-
- protected override void Dispose (bool disposing)
- {
- if (disposing)
- Close ();
-
- base.Dispose (disposing);
- }
-
- [MonoTODO]
- protected virtual void IndexListChanged(object sender, ListChangedEventArgs e)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- protected virtual void OnListChanged(ListChangedEventArgs e)
- {
- try {
- if (ListChanged != null)
- ListChanged (this, e);
- } catch {
- }
- }
-
- internal void ChangedList(ListChangedType listChangedType, int newIndex,int oldIndex)
- {
- ListChangedEventArgs e = new ListChangedEventArgs(listChangedType,newIndex,oldIndex);
- OnListChanged(e);
- }
-
- [MonoTODO]
- protected void Open()
- {
- // FIXME: create the initial index cache to the DataTable, and
- // only refresh the index when the DataTable
- // has changes via column, row, or constraint
- // changed events. the index cache is generally
- // a DataViewRow array that points to the actual
- // DataRows in the this DataTable's DataRowCollection;
- // this index is really a cache that gets
- // created during Open(), gets Updated
- // when various properties of this view
- // changes, gets Updated when this DataTable's
- // row, column, or constraint collections have changed.
- // I'm not sure what else.
- // The data view will know one of the DataTable's
- // collections have changed via one of
- // its changed events.
- // Otherwise, if getting a/the DataRowView(s),
- // Count, or other properties, then just use the
- // index cache.
- UpdateIndex (true);
- isOpen = true;
- }
-
- // internal use by Mono
- protected void Reset()
- {
- // TODO: what really happens?
- Close ();
- rowCache = null;
- Open ();
- OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1));
- }
-
-#if NET_2_0
- [MonoTODO]
- public DataTable ToTable ()
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- public DataTable ToTable (bool isDistinct, string[] columnNames)
- {
- throw new NotImplementedException ();
- }
-#endif
-
- // internal use by Mono
- protected virtual void UpdateIndex ()
- {
- UpdateIndex (false);
- }
-
- // This is method is internal to
- // the Mono implementation of DataView; it
- // is not to be used from your code.
- //
- // Update the DataRowView array which is an index cache
- // into the DataTable's DataRowCollection.
- //
- // I assume this is what UpdateIndex is used for
- protected virtual void UpdateIndex(bool force)
- {
- DataRowView[] newRowCache = null;
- DataRow[] rows = null;
-
- rows = dataTable.Select (RowFilter, Sort, RowStateFilter);
-
- newRowCache = new DataRowView[rows.Length];
- for (int r = 0; r < rows.Length; r++) {
- newRowCache[r] = new DataRowView (this, rows[r]);
- }
- rowCache = newRowCache;
- }
-
- [MonoTODO]
- PropertyDescriptorCollection ITypedList.GetItemProperties (PropertyDescriptor[] listAccessors)
- {
- // FIXME: use listAccessors somehow
-
- DataColumnPropertyDescriptor[] descriptors =
- new DataColumnPropertyDescriptor[dataTable.Columns.Count];
-
- DataColumnPropertyDescriptor descriptor;
- DataColumn dataColumn;
- for (int col = 0; col < dataTable.Columns.Count; col ++)
- {
- dataColumn = dataTable.Columns[col];
-
- descriptor = new DataColumnPropertyDescriptor(
- dataColumn.ColumnName, col, null);
- descriptor.SetComponentType (typeof (System.Data.DataRowView));
- descriptor.SetPropertyType (dataColumn.DataType);
- descriptor.SetReadOnly (dataColumn.ReadOnly);
-
- descriptors[col] = descriptor;
- }
-
- return new PropertyDescriptorCollection (descriptors);
- }
-
- [MonoTODO]
- string ITypedList.GetListName (PropertyDescriptor[] listAccessors)
- {
- return "";
- }
-
- //int ICollection.Count {
- // get {
- // return Count;
- // }
- //}
-
- bool ICollection.IsSynchronized {
- [MonoTODO]
- get {
- return false;
- }
- }
-
- object ICollection.SyncRoot {
- [MonoTODO]
- get {
- // FIXME:
- return this;
- }
- }
-
- //void ICollection.CopyTo (Array array, int index)
- //{
- // CopyTo (array, index);
- //}
-
- bool IList.IsFixedSize {
- [MonoTODO]
- get {
- return false;
- }
- }
-
- bool IList.IsReadOnly {
- [MonoTODO]
- get {
- return false;
- }
- }
-
- object IList.this[int recordIndex] {
- [MonoTODO]
- get {
- return this[recordIndex];
- }
-
- [MonoTODO]
- set{
- throw new InvalidOperationException();
- }
- }
-
- [MonoTODO]
- int IList.Add (object value)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- void IList.Clear ()
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- bool IList.Contains (object value)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- int IList.IndexOf (object value)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- void IList.Insert(int index,object value)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- void IList.Remove(object value)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- void IList.RemoveAt(int index)
- {
- throw new NotImplementedException ();
- }
-
- #region IBindingList implementation
-
- [MonoTODO]
- void IBindingList.AddIndex (PropertyDescriptor property)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- object IBindingList.AddNew ()
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- int IBindingList.Find (PropertyDescriptor property, object key)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- void IBindingList.RemoveIndex (PropertyDescriptor property)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- void IBindingList.RemoveSort ()
- {
- throw new NotImplementedException ();
- }
-
- bool IBindingList.AllowEdit {
- [MonoTODO]
- get {
- return AllowEdit;
- }
- }
-
- bool IBindingList.AllowNew {
- [MonoTODO]
- get {
- return AllowNew;
- }
- }
-
- bool IBindingList.AllowRemove {
- [MonoTODO]
- get {
- return AllowDelete;
- }
- }
-
- bool IBindingList.IsSorted {
- [MonoTODO]
- get {
- return isSorted;
- }
- }
-
- ListSortDirection IBindingList.SortDirection {
- [MonoTODO]
- get {
- // FIXME:
- return ListSortDirection.Ascending;
- }
- }
-
- PropertyDescriptor IBindingList.SortProperty {
- [MonoTODO]
- get {
- // FIXME:
- return null;
- }
- }
-
- bool IBindingList.SupportsChangeNotification {
- [MonoTODO]
- get {
- return false;
- }
- }
-
- bool IBindingList.SupportsSearching {
- [MonoTODO]
- get {
- return false;
- }
- }
-
- bool IBindingList.SupportsSorting {
- [MonoTODO]
- get {
- return false;
- }
- }
-
- #endregion // IBindingList implementation
-
- private class DataViewEnumerator : IEnumerator
- {
- private DataRowView[] rows;
- int on = -1;
-
- internal DataViewEnumerator (DataRowView[] dataRowViews)
- {
- rows = dataRowViews;
- }
-
- public object Current {
- get {
- if (on == -1 || on >= rows.Length)
- throw new InvalidOperationException ();
- return rows[on];
- }
- }
-
- public bool MoveNext ()
- {
- // TODO: how do you determine
- // if a collection has been
- // changed?
- if (on < rows.Length - 1) {
- on++;
- return true;
- }
-
- return false; // EOF
- }
-
- public void Reset () {
- on = -1;
- }
- }
- }
-}
-
+//\r
+// System.Data.DataView.cs\r
+//\r
+// Author:\r
+// Daniel Morgan <danmorg@sc.rr.com>\r
+// Tim Coleman (tim@timcoleman.com)\r
+// Punit Todi (punits_mailbox@yahoo.com)\r
+// Copyright (C) Daniel Morgan, 2002, 2003\r
+// (C) Ximian, Inc 2002\r
+// Copyright (C) Tim Coleman, 2002-2003 \r
+\r
+using System;\r
+using System.Collections;\r
+using System.ComponentModel;\r
+using System.Reflection;\r
+\r
+namespace System.Data \r
+{\r
+ /// <summary>\r
+ /// A DataView is used in the binding of data between\r
+ /// a DataTable and Windows Forms or Web Forms allowing\r
+ /// a view of a DataTable for editing, filtering,\r
+ /// navigation, searching, and sorting.\r
+ /// </summary>\r
+ //[Designer]\r
+ [Editor]\r
+ [DefaultEvent ("PositionChanged")]\r
+ [DefaultProperty ("Table")]\r
+ [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataViewDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]\r
+ public class DataView : MarshalByValueComponent, IBindingList, IList, ICollection, IEnumerable, ITypedList, ISupportInitialize\r
+ {\r
+ DataTable dataTable = null;\r
+ string rowFilter = "";\r
+ string sort = "";\r
+ DataViewRowState rowState;\r
+ DataRowView[] rowCache = null;\r
+ \r
+ \r
+ bool allowNew = true; \r
+ bool allowEdit = true;\r
+ bool allowDelete = true;\r
+ bool applyDefaultSort = false;\r
+ bool isSorted = false;\r
+\r
+ bool isOpen = false;\r
+\r
+ bool bInit = false;\r
+ bool useDefaultSort = true;\r
+ \r
+ internal DataViewManager dataViewManager = null;\r
+ #region Constructors\r
+ public DataView () \r
+ {\r
+ rowState = DataViewRowState.CurrentRows;\r
+ Open ();\r
+ }\r
+\r
+ public DataView (DataTable table) \r
+ {\r
+ dataTable = table;\r
+ rowState = DataViewRowState.CurrentRows;\r
+ Open ();\r
+ }\r
+\r
+ public DataView (DataTable table, string RowFilter,\r
+ string Sort, DataViewRowState RowState) \r
+ {\r
+ dataTable = table;\r
+ rowState = DataViewRowState.CurrentRows;\r
+ rowFilter = RowFilter;\r
+ sort = Sort;\r
+ rowState = RowState;\r
+ Open();\r
+ }\r
+ #endregion // Constructors\r
+ #region PublicProperties\r
+ [DataCategory ("Data")]\r
+ [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows deletes.")]\r
+ [DefaultValue (true)]\r
+ public bool AllowDelete {\r
+ get {\r
+ return allowDelete;\r
+ }\r
+ set {\r
+ allowDelete = value;\r
+ }\r
+ }\r
+\r
+ [DataCategory ("Data")]\r
+ [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows edits.")]\r
+ [DefaultValue (true)]\r
+ public bool AllowEdit {\r
+ get {\r
+ return allowEdit;\r
+ }\r
+ set {\r
+ allowEdit = value;\r
+ }\r
+ }\r
+\r
+ [DataCategory ("Data")]\r
+ [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows new rows to be added.")]\r
+ [DefaultValue (true)]\r
+ public bool AllowNew {\r
+ get {\r
+ return allowNew;\r
+ }\r
+ \r
+ set {\r
+ allowNew = value;\r
+ }\r
+ }\r
+\r
+ [DataCategory ("Data")]\r
+ [DataSysDescription ("Indicates whether to use the default sort if the Sort property is not set.")]\r
+ [DefaultValue (false)]\r
+ [RefreshProperties (RefreshProperties.All)]\r
+ public bool ApplyDefaultSort {\r
+ [MonoTODO]\r
+ get { \r
+ return applyDefaultSort;\r
+ }\r
+ \r
+ [MonoTODO]\r
+ set {\r
+ applyDefaultSort = value;\r
+ if (applyDefaultSort == true && (sort == null || sort == string.Empty)) {\r
+ foreach (Constraint c in dataTable.Constraints) {\r
+ if (c is UniqueConstraint) {\r
+ sort = GetSortString ((UniqueConstraint) c);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ UpdateIndex ();\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset,-1,-1));\r
+ }\r
+ }\r
+ // get the count of rows in the DataView after RowFilter \r
+ // and RowStateFilter have been applied\r
+ [Browsable (false)]\r
+ [DataSysDescription ("Returns the number of items currently in this view.")]\r
+ public int Count {\r
+ [MonoTODO]\r
+ get {\r
+ return rowCache.Length;\r
+ }\r
+ }\r
+\r
+ [Browsable (false)]\r
+ [DataSysDescription ("This returns a pointer to back to the DataViewManager that owns this DataSet (if any).")]\r
+ public DataViewManager DataViewManager {\r
+ [MonoTODO]\r
+ get {\r
+ return dataViewManager;\r
+ }\r
+ }\r
+\r
+ // Item indexer\r
+ // the compiler creates a DefaultMemeberAttribute from\r
+ // this IndexerNameAttribute\r
+ [System.Runtime.CompilerServices.IndexerName("Item")]\r
+ public DataRowView this[int recordIndex] {\r
+ [MonoTODO]\r
+ get {\r
+ return rowCache [recordIndex];\r
+ }\r
+ }\r
+\r
+ [DataCategory ("Data")]\r
+ [DataSysDescription ("Indicates an expression used to filter the data returned by this DataView.")]\r
+ [DefaultValue ("")]\r
+ public virtual string RowFilter {\r
+ [MonoTODO]\r
+ get {\r
+ return rowFilter;\r
+ }\r
+ \r
+ [MonoTODO]\r
+ set {\r
+ rowFilter = value;\r
+ UpdateIndex ();\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));\r
+ }\r
+ }\r
+\r
+ [DataCategory ("Data")]\r
+ [DataSysDescription ("Indicates the versions of data returned by this DataView.")]\r
+ [DefaultValue (DataViewRowState.CurrentRows)]\r
+ public DataViewRowState RowStateFilter {\r
+ [MonoTODO]\r
+ get {\r
+ return rowState;\r
+ }\r
+ \r
+ [MonoTODO]\r
+ set {\r
+ rowState = value;\r
+ UpdateIndex ();\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));\r
+ }\r
+ }\r
+\r
+ [DataCategory ("Data")]\r
+ [DataSysDescription ("Indicates the order in which data is returned by this DataView.")]\r
+ [DefaultValue ("")]\r
+ public string Sort {\r
+ [MonoTODO]\r
+ get {\r
+ return sort;\r
+ }\r
+ \r
+ [MonoTODO]\r
+ set {\r
+ if (value == null) { \r
+ /* if given value is null useDefaultSort */\r
+ useDefaultSort = true;\r
+ /* if ApplyDefault sort is true try appling it */\r
+ if (ApplyDefaultSort == true) {\r
+ foreach (Constraint c in dataTable.Constraints) {\r
+ if (c is UniqueConstraint) {\r
+ sort = GetSortString ((UniqueConstraint)c);\r
+ break;\r
+ }\r
+ }\r
+ \r
+ }\r
+ }\r
+ else { \r
+ /* else donot useDefaultSort. set it as false */\r
+ /* sort is set to value specified */\r
+ useDefaultSort = false;\r
+ sort = value;\r
+ }\r
+ UpdateIndex ();\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));\r
+ }\r
+ }\r
+\r
+ [DataCategory ("Data")]\r
+ [DataSysDescription ("Indicates the table this DataView uses to get data.")]\r
+ [DefaultValue (null)]\r
+ [RefreshProperties (RefreshProperties.All)]\r
+ public DataTable Table {\r
+ [MonoTODO]\r
+ get {\r
+ return dataTable;\r
+ }\r
+ \r
+ [MonoTODO]\r
+ set {\r
+ if (value != null && value.TableName.Equals("")) {\r
+ throw new DataException("Cannot bind to DataTable with no name.");\r
+ }\r
+\r
+ if (dataTable != null) {\r
+ UnregisterEventHandlers();\r
+ }\r
+\r
+ dataTable = value;\r
+\r
+ if (dataTable != null) {\r
+ RegisterEventHandlers();\r
+ UpdateIndex ();\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));\r
+ }\r
+ }\r
+ }\r
+ #endregion // PublicProperties\r
+ \r
+ #region PublicMethods\r
+ [MonoTODO]\r
+ public virtual DataRowView AddNew() \r
+ {\r
+ if (!IsOpen)\r
+ throw new DataException ("DataView is not open.");\r
+ if (!AllowNew)\r
+ throw new DataException ("Cannot call AddNew on a DataView where AllowNew is false.");\r
+ \r
+ DataRow row = dataTable.NewRow ();\r
+ if (row == null)\r
+ throw new Exception ("Row not created");\r
+ DataRowView rowView = new DataRowView (this, row, true);\r
+ \r
+ dataTable.Rows.Add (row);\r
+ return rowView;\r
+ }\r
+\r
+ [MonoTODO]\r
+ public void BeginInit() \r
+ {\r
+ bInit = true; \r
+ // FIXME:\r
+ }\r
+\r
+ [MonoTODO]\r
+ public void CopyTo (Array array, int index) \r
+ {\r
+ int row = 0;\r
+ for (; row < rowCache.Length && row < array.Length; row++) {\r
+ array.SetValue (rowCache[row], index + row);\r
+ }\r
+ }\r
+\r
+ public void Delete(int index) \r
+ {\r
+ if (!IsOpen)\r
+ throw new DataException ("DataView is not open.");\r
+ if (!AllowDelete)\r
+ throw new DataException ("Cannot delete on a DataSource where AllowDelete is false.");\r
+ \r
+ if (index > rowCache.Length)\r
+ throw new IndexOutOfRangeException ("There is no row at " +\r
+ "position: " + index + ".");\r
+ DataRowView row = rowCache [index];\r
+ row.Row.Delete ();\r
+ }\r
+\r
+#if NET_2_0\r
+ [MonoTODO]\r
+ public virtual bool Equals (DataView dv)\r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+#endif\r
+\r
+ [MonoTODO]\r
+ public void EndInit() \r
+ {\r
+ bInit = false;\r
+ // FIXME:\r
+ }\r
+\r
+ public int Find(object key) \r
+ {\r
+ object [] keys = new object[1];\r
+ keys[0] = key;\r
+ return Find(keys);\r
+ }\r
+ \r
+ public int Find(object[] key) \r
+ {\r
+ int index; \r
+ if (sort == null || sort == string.Empty)\r
+ throw new ArgumentException ("Find finds a row based on a Sort order, and no Sort order is specified");\r
+ else {\r
+ DataTable.SortableColumn [] sortedColumns = null;\r
+ sortedColumns = dataTable.ParseTheSortString (sort);\r
+ if (sortedColumns == null)\r
+ throw new Exception ("sort expression result is null");\r
+ if (sortedColumns.Length == 0)\r
+ throw new Exception ("sort expression result is 0");\r
+ if (sortedColumns.Length != key.Length)\r
+ throw new ArgumentException ("Expecting " + sortedColumns.Length +\r
+ " value(s) from the key being indexed, but recieved "+\r
+ key.Length+" value(s).");\r
+ RowComparer rowComparer = new RowComparer (dataTable,sortedColumns);\r
+ int searchResult = Array.BinarySearch (rowCache,key,rowComparer);\r
+ if (searchResult < 0)\r
+ return -1;\r
+ else\r
+ return searchResult;\r
+ }\r
+ }\r
+ \r
+ [MonoTODO]\r
+ public DataRowView[] FindRows(object key) \r
+ {\r
+ // FIXME: use an index cache to the DataTable, and \r
+ // only refresh the index when the DataTable\r
+ // has changes via column, row, or constraint\r
+ // changed events\r
+\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ public DataRowView[] FindRows(object[] key) \r
+ {\r
+ // FIXME: use an index cache to the DataTable, and \r
+ // only refresh the index when the DataTable\r
+ // has changes via column, row, or constraint\r
+ // changed events\r
+ \r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ public IEnumerator GetEnumerator() \r
+ {\r
+ return new DataViewEnumerator (rowCache);\r
+ }\r
+ #endregion // PublicMethods\r
+ \r
+ [MonoTODO]\r
+ [DataCategory ("Data")]\r
+ [DataSysDescription ("Indicates the data returned by this DataView has somehow changed.")]\r
+ public event ListChangedEventHandler ListChanged;\r
+\r
+ protected bool IsOpen {\r
+ [MonoTODO]\r
+ get {\r
+ return isOpen;\r
+ }\r
+ }\r
+\r
+ [MonoTODO]\r
+ protected void Close() \r
+ {\r
+ // FIXME:\r
+ isOpen = false;\r
+ }\r
+\r
+ [MonoTODO]\r
+ protected virtual void ColumnCollectionChanged (object sender, \r
+ CollectionChangeEventArgs e) \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ protected override void Dispose (bool disposing) \r
+ {\r
+ if (disposing)\r
+ Close ();\r
+\r
+ base.Dispose (disposing);\r
+ }\r
+\r
+ [MonoTODO]\r
+ protected virtual void IndexListChanged(object sender, ListChangedEventArgs e) \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ protected virtual void OnListChanged(ListChangedEventArgs e) \r
+ {\r
+ try {\r
+ if (ListChanged != null)\r
+ ListChanged (this, e);\r
+ } catch {\r
+ }\r
+ }\r
+\r
+ internal void ChangedList(ListChangedType listChangedType, int newIndex,int oldIndex)\r
+ {\r
+ ListChangedEventArgs e = new ListChangedEventArgs(listChangedType,newIndex,oldIndex);\r
+ OnListChanged(e);\r
+ }\r
+\r
+ [MonoTODO]\r
+ protected void Open() \r
+ {\r
+ // FIXME: create the initial index cache to the DataTable, and \r
+ // only refresh the index when the DataTable\r
+ // has changes via column, row, or constraint\r
+ // changed events. the index cache is generally\r
+ // a DataViewRow array that points to the actual\r
+ // DataRows in the this DataTable's DataRowCollection;\r
+ // this index is really a cache that gets \r
+ // created during Open(), gets Updated \r
+ // when various properties of this view\r
+ // changes, gets Updated when this DataTable's \r
+ // row, column, or constraint collections have changed.\r
+ // I'm not sure what else.\r
+ // The data view will know one of the DataTable's\r
+ // collections have changed via one of \r
+ // its changed events.\r
+ // Otherwise, if getting a/the DataRowView(s),\r
+ // Count, or other properties, then just use the\r
+ // index cache.\r
+ // dataTable.ColumnChanged += new DataColumnChangeEventHandler(OnColumnChanged);\r
+ if (dataTable != null) {\r
+ RegisterEventHandlers();\r
+ UpdateIndex (true);\r
+ }\r
+ isOpen = true;\r
+ }\r
+ \r
+ private void RegisterEventHandlers()\r
+ {\r
+ dataTable.RowChanged += new DataRowChangeEventHandler(OnRowChanged);\r
+ dataTable.RowDeleted += new DataRowChangeEventHandler(OnRowDeleted);\r
+ dataTable.Columns.CollectionChanged += new CollectionChangeEventHandler(OnColumnCollectionChanged);\r
+ dataTable.Constraints.CollectionChanged += new CollectionChangeEventHandler(OnConstraintCollectionChanged);\r
+ }\r
+\r
+ private void UnregisterEventHandlers()\r
+ {\r
+ dataTable.RowChanged -= new DataRowChangeEventHandler(OnRowChanged);\r
+ dataTable.RowDeleted -= new DataRowChangeEventHandler(OnRowDeleted);\r
+ dataTable.Columns.CollectionChanged -= new CollectionChangeEventHandler(OnColumnCollectionChanged);\r
+ dataTable.Constraints.CollectionChanged -= new CollectionChangeEventHandler(OnConstraintCollectionChanged);\r
+ }\r
+ \r
+ private void OnColumnChanged(object sender, DataColumnChangeEventArgs args)\r
+ { /* not used */\r
+ UpdateIndex(true);\r
+ }\r
+ \r
+ private void OnRowChanged(object sender, DataRowChangeEventArgs args)\r
+ {\r
+ int oldIndex,newIndex;\r
+ oldIndex = newIndex = -1;\r
+ oldIndex = IndexOf (args.Row);\r
+ UpdateIndex (true);\r
+ newIndex = IndexOf (args.Row);\r
+\r
+ /* ItemAdded */\r
+ if(args.Action == DataRowAction.Add)\r
+ { \r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, newIndex, -1));\r
+ }\r
+ \r
+ /* ItemChanged or ItemMoved */\r
+ if (args.Action == DataRowAction.Change) { \r
+ if (oldIndex == newIndex)\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, newIndex, -1)); \r
+ else\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.ItemMoved, newIndex, oldIndex)); \r
+ }\r
+ }\r
+ \r
+ private void OnRowDeleted (object sender, DataRowChangeEventArgs args)\r
+ {\r
+ /* ItemDeleted */\r
+ int newIndex;\r
+ newIndex = IndexOf (args.Row);\r
+ UpdateIndex (true);\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, newIndex, -1));\r
+ }\r
+ \r
+ private void OnColumnCollectionChanged (object sender, CollectionChangeEventArgs args)\r
+ {\r
+ UpdateIndex (true);\r
+ /* PropertyDescriptor Add */\r
+ if (args.Action == CollectionChangeAction.Add)\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorAdded,0,0));\r
+ /* PropertyDescriptor Removed */\r
+ if (args.Action == CollectionChangeAction.Remove)\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorDeleted,0,0));\r
+ /* FIXME: PropertyDescriptor Changed ???*/\r
+ if (args.Action == CollectionChangeAction.Refresh)\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged,0,0));\r
+ }\r
+ private void OnConstraintCollectionChanged(object sender, CollectionChangeEventArgs args)\r
+ {\r
+ // The Sort variable is set to the UniqueConstraint column.\r
+ // if ApplyDefault Sort is true and Sort is null or is not set Explicitly\r
+ \r
+ // FIXME: The interal cache may change as result of change in Constraint collection\r
+ // one such scenerio is taken care.\r
+ // There may be more. I dont know what else can be done.\r
+ /* useDefaultSort is set to false when Sort is set explicitly */\r
+ if (args.Action == CollectionChangeAction.Add && args.Element is UniqueConstraint) {\r
+ if (ApplyDefaultSort == true && useDefaultSort == true)\r
+ Sort = GetSortString ((UniqueConstraint) args.Element);\r
+ }\r
+ UpdateIndex (true);\r
+ /* ItemReset */\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset,-1,-1));\r
+ }\r
+\r
+ // internal use by Mono\r
+ protected void Reset() \r
+ {\r
+ // TODO: what really happens?\r
+ Close ();\r
+ rowCache = null;\r
+ Open ();\r
+ OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1 ));\r
+ }\r
+\r
+#if NET_2_0\r
+ [MonoTODO]\r
+ public DataTable ToTable ()\r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ public DataTable ToTable (bool isDistinct, string[] columnNames)\r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+#endif\r
+\r
+ // internal use by Mono\r
+ protected virtual void UpdateIndex () \r
+ {\r
+ UpdateIndex (false);\r
+ }\r
+\r
+ // This is method is internal to \r
+ // the Mono implementation of DataView; it\r
+ // is not to be used from your code.\r
+ //\r
+ // Update the DataRowView array which is an index cache\r
+ // into the DataTable's DataRowCollection.\r
+ //\r
+ // I assume this is what UpdateIndex is used for\r
+ protected virtual void UpdateIndex(bool force) \r
+ {\r
+ DataRowView[] newRowCache = null;\r
+ DataRow[] rows = null;\r
+ \r
+ rows = dataTable.Select (RowFilter, Sort, RowStateFilter);\r
+\r
+ newRowCache = new DataRowView[rows.Length];\r
+ for (int r = 0; r < rows.Length; r++) {\r
+ newRowCache[r] = new DataRowView (this, rows[r]);\r
+ }\r
+ rowCache = newRowCache;\r
+ }\r
+\r
+ [MonoTODO]\r
+ PropertyDescriptorCollection ITypedList.GetItemProperties (PropertyDescriptor[] listAccessors) \r
+ {\r
+ // FIXME: use listAccessors somehow\r
+ DataColumnPropertyDescriptor [] descriptors = \r
+ new DataColumnPropertyDescriptor [dataTable.Columns.Count];\r
+\r
+ DataColumnPropertyDescriptor descriptor;\r
+ DataColumn dataColumn;\r
+ for (int col = 0; col < dataTable.Columns.Count; col ++) {\r
+ dataColumn = dataTable.Columns[col];\r
+ descriptor = new DataColumnPropertyDescriptor(\r
+ dataColumn.ColumnName, col, null);\r
+ descriptor.SetComponentType (typeof (System.Data.DataRowView));\r
+ descriptor.SetPropertyType (dataColumn.DataType);\r
+ descriptor.SetReadOnly (dataColumn.ReadOnly);\r
+ descriptors [col] = descriptor;\r
+ }\r
+ return new PropertyDescriptorCollection (descriptors);\r
+ }\r
+\r
+ [MonoTODO]\r
+ string ITypedList.GetListName (PropertyDescriptor[] listAccessors) \r
+ {\r
+ return "";\r
+ }\r
+\r
+ //int ICollection.Count { \r
+ // get {\r
+ // return Count;\r
+ // } \r
+ //}\r
+\r
+ bool ICollection.IsSynchronized { \r
+ [MonoTODO]\r
+ get {\r
+ return false;\r
+ } \r
+ }\r
+\r
+ object ICollection.SyncRoot { \r
+ [MonoTODO]\r
+ get {\r
+ // FIXME:\r
+ return this;\r
+ }\r
+ }\r
+\r
+ //void ICollection.CopyTo (Array array, int index) \r
+ //{\r
+ // CopyTo (array, index);\r
+ //}\r
+\r
+ bool IList.IsFixedSize {\r
+ [MonoTODO]\r
+ get {\r
+ return false;\r
+ }\r
+ }\r
+ \r
+ bool IList.IsReadOnly {\r
+ [MonoTODO]\r
+ get {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ object IList.this[int recordIndex] {\r
+ [MonoTODO]\r
+ get {\r
+ return this[recordIndex];\r
+ }\r
+\r
+ [MonoTODO]\r
+ set{\r
+ throw new InvalidOperationException();\r
+ }\r
+ }\r
+\r
+ [MonoTODO]\r
+ int IList.Add (object value) \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ void IList.Clear () \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ bool IList.Contains (object value) \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ int IList.IndexOf (object value) \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+ \r
+ [MonoTODO]\r
+ void IList.Insert(int index,object value) \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ void IList.Remove(object value) \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ void IList.RemoveAt(int index) \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ #region IBindingList implementation\r
+\r
+ [MonoTODO]\r
+ void IBindingList.AddIndex (PropertyDescriptor property) \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ object IBindingList.AddNew () \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction) \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ int IBindingList.Find (PropertyDescriptor property, object key) \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ void IBindingList.RemoveIndex (PropertyDescriptor property) \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+\r
+ [MonoTODO]\r
+ void IBindingList.RemoveSort () \r
+ {\r
+ throw new NotImplementedException ();\r
+ }\r
+ \r
+ bool IBindingList.AllowEdit {\r
+ [MonoTODO]\r
+ get {\r
+ return AllowEdit;\r
+ }\r
+ }\r
+\r
+ bool IBindingList.AllowNew {\r
+ [MonoTODO]\r
+ get {\r
+ return AllowNew;\r
+ }\r
+ }\r
+\r
+ bool IBindingList.AllowRemove {\r
+ [MonoTODO]\r
+ get {\r
+ return AllowDelete;\r
+ }\r
+ }\r
+\r
+ bool IBindingList.IsSorted {\r
+ [MonoTODO]\r
+ get {\r
+ return isSorted;\r
+ }\r
+ }\r
+\r
+ ListSortDirection IBindingList.SortDirection {\r
+ [MonoTODO]\r
+ get {\r
+ // FIXME: \r
+ return ListSortDirection.Ascending;\r
+ }\r
+ }\r
+\r
+ PropertyDescriptor IBindingList.SortProperty {\r
+ [MonoTODO]\r
+ get {\r
+ // FIXME:\r
+ return null;\r
+ }\r
+ }\r
+\r
+ bool IBindingList.SupportsChangeNotification {\r
+ [MonoTODO]\r
+ get {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ bool IBindingList.SupportsSearching {\r
+ [MonoTODO]\r
+ get {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ bool IBindingList.SupportsSorting {\r
+ [MonoTODO]\r
+ get {\r
+ return false;\r
+ }\r
+ }\r
+\r
+ #endregion // IBindingList implementation\r
+ private int IndexOf(DataRow dr)\r
+ {\r
+ for (int i=0; i < rowCache.Length; i++)\r
+ if (dr.Equals (rowCache [i].Row))\r
+ return i;\r
+ return -1;\r
+ }\r
+ \r
+ private string GetSortString (UniqueConstraint uc)\r
+ {\r
+ string sortKey = null;\r
+ foreach (DataColumn dc in uc.Columns)\r
+ sortKey += dc.ColumnName + ", ";\r
+ sortKey = sortKey.Substring (0,sortKey.Length - 2);\r
+ return sortKey;\r
+ }\r
+ \r
+ private object [] GetSearchKey (DataRow dr)\r
+ {\r
+ DataTable.SortableColumn [] sortedColumns = null;\r
+ sortedColumns = dataTable.ParseTheSortString (sort);\r
+ if (sortedColumns == null) \r
+ return null;\r
+ object [] keys = new object [sortedColumns.Length];\r
+ int i = 0;\r
+ foreach (DataTable.SortableColumn sc in sortedColumns) {\r
+ keys [i] = dr [sc.Column];\r
+ i++;\r
+ }\r
+ return keys;\r
+ }\r
+\r
+ private class DataViewEnumerator : IEnumerator \r
+ {\r
+ private DataRowView [] rows;\r
+ int on = -1;\r
+\r
+ internal DataViewEnumerator (DataRowView [] dataRowViews) \r
+ {\r
+ rows = dataRowViews;\r
+ }\r
+\r
+ public object Current {\r
+ get {\r
+ if (on == -1 || on >= rows.Length)\r
+ throw new InvalidOperationException ();\r
+ return rows [on];\r
+ }\r
+ }\r
+\r
+ public bool MoveNext () \r
+ {\r
+ // TODO: how do you determine\r
+ // if a collection has been\r
+ // changed?\r
+ if (on < rows.Length - 1) {\r
+ on++;\r
+ return true;\r
+ }\r
+\r
+ return false; // EOF\r
+ }\r
+\r
+ public void Reset () {\r
+ on = -1;\r
+ }\r
+ }\r
+ \r
+ private class RowComparer : IComparer \r
+ {\r
+ private DataTable.SortableColumn [] sortColumns;\r
+ private DataTable table;\r
+ public RowComparer(DataTable table, DataTable.SortableColumn[] sortColumns) \r
+ {\r
+ this.table = table; \r
+ this.sortColumns = sortColumns;\r
+ }\r
+\r
+ public DataTable.SortableColumn[] SortedColumns {\r
+ get {\r
+ return sortColumns;\r
+ }\r
+ }\r
+ \r
+ int IComparer.Compare (object x, object y) \r
+ {\r
+ if(x == null)\r
+ throw new Exception ("Object to compare is null: x");\r
+ if(y == null)\r
+ throw new Exception ("Object to compare is null: y");\r
+ DataRowView rowView = (DataRowView) y;\r
+ object [] keys = (object [])x;\r
+ for(int i = 0; i < sortColumns.Length; i++) {\r
+ DataTable.SortableColumn sortColumn = sortColumns [i];\r
+ DataColumn dc = sortColumn.Column;\r
+\r
+ IComparable row = (IComparable) rowView.Row [dc];\r
+ object key = keys [i];\r
+ \r
+ int result = CompareObjects (key,row);\r
+ if (result != 0) {\r
+ if (sortColumn.SortDirection == ListSortDirection.Ascending)\r
+ return result;\r
+ else \r
+ return -result;\r
+ }\r
+ }\r
+ return 0;\r
+ }\r
+\r
+ private int CompareObjects (object a, object b) \r
+ {\r
+ if (a == b)\r
+ return 0;\r
+ else if (a == null)\r
+ return -1;\r
+ else if (a == DBNull.Value)\r
+ return -1;\r
+ else if (b == null)\r
+ return 1;\r
+ else if (b == DBNull.Value)\r
+ return 1;\r
+\r
+ if((a is string) && (b is string)) {\r
+ a = ((string) a).ToUpper (table.Locale);\r
+ b = ((string) b).ToUpper (table.Locale); \r
+ }\r
+\r
+ if (a is IComparable)\r
+ return ((a as IComparable).CompareTo (b));\r
+ else if (b is IComparable)\r
+ return -((b as IComparable).CompareTo (a));\r
+\r
+ throw new ArgumentException ("Neither a nor b IComparable");\r
+ }\r
+ }\r
+\r
+ }\r
+}\r