2005-01-24 Atsushi Enomoto <atsushi@ximian.com>
authorAtsushi Eno <atsushieno@gmail.com>
Mon, 24 Jan 2005 14:35:32 +0000 (14:35 -0000)
committerAtsushi Eno <atsushieno@gmail.com>
Mon, 24 Jan 2005 14:35:32 +0000 (14:35 -0000)
* DataTable.cs, DataView.cs :
  Optimized DataView to compile only once RowFilter and Sort when
  those properties are set. To make it possible, extracted
  SortableColumn out of DataTable and added internal DataTable.Select()
  that accepts precompiled IExpression and SortableColumns[].

svn path=/trunk/mcs/; revision=39409

mcs/class/System.Data/System.Data/ChangeLog
mcs/class/System.Data/System.Data/DataTable.cs
mcs/class/System.Data/System.Data/DataView.cs

index bdd8b0832b4321c32f6dbf3e505d790b5b3b1915..22ec69532c2c3361c0deb2865c171ca339c336b9 100644 (file)
@@ -1,3 +1,11 @@
+2005-01-24  Atsushi Enomoto  <atsushi@ximian.com>
+
+       * DataTable.cs, DataView.cs :
+         Optimized DataView to compile only once RowFilter and Sort when 
+         those properties are set. To make it possible, extracted 
+         SortableColumn out of DataTable and added internal DataTable.Select()
+         that accepts precompiled IExpression and SortableColumns[].
+
 2005-01-24  Atsushi Enomoto  <atsushi@ximian.com>
 
        * DataColumn.cs : set_MaxLength is not allowed when it is mapped to
        * DataSet.cs (Copy, Clone): The Relations of the DataSet were not copy.
        (HasChanges, Reset): Imlementation.
        
-       * DataTable.cs (HasErrors): There is no flag for errors, instead the table ask her row if they have any errors.\r
+       * DataTable.cs (HasErrors): There is no flag for errors, instead the table ask her row if they have any errors.
        This is because the we do not no when to turn off the flag.
        (Locale): Changing implementation to behave like ADO.NET.
        (AcceptChanges): Fix bug.
        (HasVersion): Added special treatment for special RowState.
        (CollectionChanged): More checks to avoid NullReferenceException.
        
-       * DataRowCollection.cs (Remove): Fix a bug.\r
+       * DataRowCollection.cs (Remove): Fix a bug.
 
 
 2003-10-01  Duncan Mak  <duncan@ximian.com>
index c47c543f500c2f603de810d5f58439ad3a6d7232..c9fb8b6a50d8deb7d7bc5eda6a822fe5ae61eee3 100644 (file)
@@ -195,15 +195,6 @@ namespace System.Data {
                        }
                }
 
-               internal bool VirginCaseSensitive {
-                       get { return _virginCaseSensitive; }
-                       set { _virginCaseSensitive = value; }
-               }
-
-               internal ArrayList Indexes{
-                       get { return _indexes; }
-               }
-
                internal void ChangedDataColumn (DataRow dr, DataColumn dc, object pv) 
                {
                        DataColumnChangeEventArgs e = new DataColumnChangeEventArgs (dr, dc, pv);
@@ -750,7 +741,7 @@ namespace System.Data {
                {
                                        
                        Copy.CaseSensitive = CaseSensitive;
-                       Copy.VirginCaseSensitive = VirginCaseSensitive;
+                       Copy._virginCaseSensitive = _virginCaseSensitive;
 
                        // Copy.ChildRelations
                        // Copy.Constraints
@@ -1285,7 +1276,15 @@ namespace System.Data {
                                Parser parser = new Parser ();
                                filter = parser.Compile (filterExpression);
                        }
+                       SortableColumn[] sortableColumns = null;
+                       if (sort != null && !sort.Equals(String.Empty))
+                               sortableColumns = SortableColumn.ParseSortString (this, sort, true);
 
+                       return Select (filter, sortableColumns, recordStates);
+               }
+
+               internal DataRow [] Select (IExpression filter, SortableColumn [] sortableColumns, DataViewRowState recordStates)
+               {
                        ArrayList rowList = new ArrayList();
                        int recordStateFilter = GetRowStateFilter(recordStates);
                        foreach (DataRow row in Rows) {
@@ -1298,16 +1297,7 @@ namespace System.Data {
 
                        DataRow[] dataRows = (DataRow[])rowList.ToArray(typeof(DataRow));
 
-                       if (sort != null && !sort.Equals(String.Empty)) 
-                       {
-                               SortableColumn[] sortableColumns = null;
-
-                               sortableColumns = ParseTheSortString (sort);
-                               if (sortableColumns == null)
-                                       throw new Exception ("sort expression result is null");
-                               if (sortableColumns.Length == 0)
-                                       throw new Exception("sort expression result is 0");
-
+                       if (sortableColumns != null) {
                                RowSorter rowSorter = new RowSorter (this, dataRows, sortableColumns);
                                dataRows = rowSorter.SortRows ();
 
@@ -1315,7 +1305,6 @@ namespace System.Data {
                                rowSorter = null;
                        }
 
-                       
                        return dataRows;
                }
 
@@ -1673,82 +1662,6 @@ namespace System.Data {
                        UniqueConstraint.SetAsPrimaryKey(this.Constraints, null);
                }
 
-               // to parse the sort string for DataTable:Select(expression,sort)
-               // into sortable columns (think ORDER BY, 
-               // such as, "customer ASC, price DESC" )
-               internal SortableColumn[] ParseTheSortString (string sort) 
-               {
-                       SortableColumn[] sortColumns = null;
-                       ArrayList columns = null;
-               
-                       if (sort != null && !sort.Equals ("")) {
-                               columns = new ArrayList ();
-                               string[] columnExpression = sort.Trim ().Split (new char[1] {','});
-                       
-                               for (int c = 0; c < columnExpression.Length; c++) {
-                                       string[] columnSortInfo = columnExpression[c].Trim ().Split (new char[1] {' '});
-                               
-                                       string columnName = columnSortInfo[0].Trim ();
-                                       string sortOrder = "ASC";
-                                       if (columnSortInfo.Length > 1) 
-                                               sortOrder = columnSortInfo[1].Trim ().ToUpper (Locale);
-                                       
-                                       ListSortDirection sortDirection = ListSortDirection.Ascending;
-                                       switch (sortOrder) {
-                                       case "ASC":
-                                               sortDirection = ListSortDirection.Ascending;
-                                               break;
-                                       case "DESC":
-                                               sortDirection = ListSortDirection.Descending;
-                                               break;
-                                       default:
-                                               throw new IndexOutOfRangeException ("Could not find column: " + columnExpression[c]);
-                                       }
-                                       Int32 ord = 0;
-                                       try {
-                                               ord = Int32.Parse (columnName);
-                                       }
-                                       catch (FormatException) {
-                                               ord = -1;
-                                       }
-                                       DataColumn dc = null;
-                                       if (ord == -1)                          
-                                               dc = _columnCollection[columnName];
-                                       else
-                                               dc = _columnCollection[ord];
-                                       SortableColumn sortCol = new SortableColumn (dc,sortDirection);
-                                       columns.Add (sortCol);
-                               }       
-                               sortColumns = (SortableColumn[]) columns.ToArray (typeof (SortableColumn));
-                       }               
-                       return sortColumns;
-               }
-       
-               internal class SortableColumn 
-               {
-                       private DataColumn col;
-                       private ListSortDirection dir;
-
-                       internal SortableColumn (DataColumn column, 
-                                               ListSortDirection direction) 
-                       {
-                               col = column;
-                               dir = direction;
-                       }
-
-                       public DataColumn Column {
-                               get {
-                                       return col;
-                               }
-                       }
-
-                       public ListSortDirection SortDirection {
-                               get {
-                                       return dir;
-                               }
-                       }
-               }
-
                private class RowSorter : IComparer 
                {
                        private DataTable table;
@@ -1912,4 +1825,88 @@ namespace System.Data {
                        }
                }
        }
+
+       // to parse the sort string for DataTable:Select(expression,sort)
+       // into sortable columns (think ORDER BY, 
+       // such as, "customer ASC, price DESC" ), as well as DataView.Sort.
+       internal class SortableColumn 
+       {
+               private DataColumn col;
+               private ListSortDirection dir;
+
+               internal SortableColumn (DataColumn column, 
+                                       ListSortDirection direction) 
+               {
+                       col = column;
+                       dir = direction;
+               }
+
+               public DataColumn Column {
+                       get {
+                               return col;
+                       }
+               }
+
+               public ListSortDirection SortDirection {
+                       get {
+                               return dir;
+                       }
+               }
+
+               internal static SortableColumn[] ParseSortString (DataTable table, string sort, bool rejectNoResult)
+               {
+                       SortableColumn[] sortColumns = null;
+                       ArrayList columns = null;
+               
+                       if (sort != null && !sort.Equals ("")) {
+                               columns = new ArrayList ();
+                               string[] columnExpression = sort.Trim ().Split (new char[1] {','});
+                       
+                               for (int c = 0; c < columnExpression.Length; c++) {
+                                       string[] columnSortInfo = columnExpression[c].Trim ().Split (new char[1] {' '});
+                               
+                                       string columnName = columnSortInfo[0].Trim ();
+                                       string sortOrder = "ASC";
+                                       if (columnSortInfo.Length > 1) 
+                                               sortOrder = columnSortInfo[1].Trim ().ToUpper (table.Locale);
+                                       
+                                       ListSortDirection sortDirection = ListSortDirection.Ascending;
+                                       switch (sortOrder) {
+                                       case "ASC":
+                                               sortDirection = ListSortDirection.Ascending;
+                                               break;
+                                       case "DESC":
+                                               sortDirection = ListSortDirection.Descending;
+                                               break;
+                                       default:
+                                               throw new IndexOutOfRangeException ("Could not find column: " + columnExpression[c]);
+                                       }
+                                       Int32 ord = 0;
+                                       try {
+                                               ord = Int32.Parse (columnName);
+                                       }
+                                       catch (FormatException) {
+                                               ord = -1;
+                                       }
+                                       DataColumn dc = null;
+                                       if (ord == -1)                          
+                                               dc = table.Columns [columnName];
+                                       else
+                                               dc = table.Columns [ord];
+                                       SortableColumn sortCol = new SortableColumn (dc,sortDirection);
+                                       columns.Add (sortCol);
+                               }       
+                               sortColumns = (SortableColumn[]) columns.ToArray (typeof (SortableColumn));
+                       }               
+
+                       if (rejectNoResult) {
+                               if (sortColumns == null)
+                                       throw new Exception ("sort expression result is null");
+                               if (sortColumns.Length == 0)
+                                       throw new Exception("sort expression result is 0");
+                       }
+                       return sortColumns;
+               }
+       }
+
 }
index 7e4f34cad0eb9f3099942b562b9549bae439d05e..ec8b848de2b6f594d4f1b3041b89d08b85a70cff 100644 (file)
-//\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 = new DataRowView[0];\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 = new DataRowView[0];\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
+//
+// System.Data.DataView.cs
+//
+// Author:
+//    Daniel Morgan <danmorg@sc.rr.com>
+//    Tim Coleman (tim@timcoleman.com)
+//    Punit Todi (punits_mailbox@yahoo.com)
+// Copyright (C) Daniel Morgan, 2002, 2003
+// (C) Ximian, Inc 2002
+// Copyright (C) Tim Coleman, 2002-2003                
+
+using System;
+using System.Collections;
+using System.ComponentModel;
+using System.Reflection;
+using Mono.Data.SqlExpressions;
+
+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 = "";
+               IExpression rowFilterExpr;
+               string sort = "";
+               SortableColumn [] sortedColumns = null;
+               DataViewRowState rowState;
+               DataRowView[] rowCache = new DataRowView[0];
+
+               bool allowNew = true; 
+               bool allowEdit = true;
+               bool allowDelete = true;
+               bool applyDefaultSort = false;
+               bool isSorted = false;
+
+               bool isOpen = false;
+
+               bool bInit = false;
+               bool useDefaultSort = true;
+               
+               internal DataViewManager dataViewManager = null;
+               #region Constructors
+               public DataView () 
+               {
+                       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;
+                       this.RowFilter = RowFilter;
+                       this.Sort = Sort;
+                       rowState = RowState;
+                       Open();
+               }
+               #endregion // Constructors
+               #region PublicProperties
+               [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;
+                               if (applyDefaultSort == true && (sort == null || sort == string.Empty)) {
+                                       foreach (Constraint c in dataTable.Constraints) {
+                                               if (c is UniqueConstraint) {
+                                                       // FIXME: Compute SortableColumns[] directly.
+                                                       Sort = GetSortString ((UniqueConstraint) c);
+                                                       break;
+                                               }
+                                       }
+                               }
+                               UpdateIndex ();
+                               OnListChanged (new ListChangedEventArgs (ListChangedType.Reset,-1,-1));
+                       }
+               }
+               // 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 {
+                               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 {
+                               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 {
+                               if (value == null)
+                                       value = String.Empty;
+                               if (value == String.Empty) 
+                                       rowFilterExpr = null;
+                               else {
+                                       Parser parser = new Parser ();
+                                       rowFilterExpr = parser.Compile (value);
+                               }
+                               rowFilter = value;
+                               UpdateIndex ();
+                               OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));
+                       }
+               }
+
+               [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;
+                               UpdateIndex ();
+                               OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));
+                       }
+               }
+
+               [DataCategory ("Data")]
+               [DataSysDescription ("Indicates the order in which data is returned by this DataView.")]
+               [DefaultValue ("")]
+               public string Sort {
+                       [MonoTODO]
+                       get {
+                               return sort;
+                       }
+                       
+                       [MonoTODO]
+                       set {
+                               if (value == null) {    
+                               /* if given value is null useDefaultSort */
+                                       useDefaultSort = true;
+                                       /* if ApplyDefault sort is true try appling it */
+                                       if (ApplyDefaultSort == true) {
+                                               foreach (Constraint c in dataTable.Constraints) {
+                                                       if (c is UniqueConstraint) {
+                                                               // FIXME: Compute SortableColumns[] directly.
+                                                               Sort = GetSortString ((UniqueConstraint)c);
+                                                               break;
+                                                       }
+                                               }
+                                               
+                                       }
+                               }
+                               else {  
+                                       /* else donot useDefaultSort. set it as false */
+                                       /* sort is set to value specified */
+                                       useDefaultSort = false;
+                                       sort = value;
+                                       sortedColumns = SortableColumn.ParseSortString (dataTable, value, true);
+                               }
+                               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)]
+               public DataTable Table {
+                       [MonoTODO]
+                       get {
+                               return dataTable;
+                       }
+                       
+                       [MonoTODO]
+                       set {
+                               if (value != null && value.TableName.Equals("")) {
+                                       throw new DataException("Cannot bind to DataTable with no name.");
+                               }
+
+                               if (dataTable != null) {
+                                       UnregisterEventHandlers();
+                               }
+
+                               dataTable = value;
+
+                               if (dataTable != null) {
+                                       RegisterEventHandlers();
+                                       UpdateIndex ();
+                                       OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, - 1, -1));
+                               }
+                       }
+               }
+               #endregion // PublicProperties
+               
+               #region PublicMethods
+               [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 ();
+                       if (row == null)
+                               throw new Exception ("Row not created");
+                       DataRowView rowView = new DataRowView (this, row, true);
+                       
+                       dataTable.Rows.Add (row);
+                       return rowView;
+               }
+
+               [MonoTODO]
+               public void BeginInit() 
+               {
+                       bInit = true; 
+                       // FIXME:
+               }
+
+               [MonoTODO]
+               public void CopyTo (Array array, int index) 
+               {
+                       int row = 0;
+                       for (; row < rowCache.Length && row < array.Length; row++) {
+                               array.SetValue (rowCache[row], index + row);
+                       }
+               }
+
+               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.");
+                       
+                       if (index > rowCache.Length)
+                               throw new IndexOutOfRangeException ("There is no row at " +
+                                               "position: " + index + ".");
+                       DataRowView row = rowCache [index];
+                       row.Row.Delete ();
+               }
+
+#if NET_2_0
+               [MonoTODO]
+               public virtual bool Equals (DataView dv)
+               {
+                       throw new NotImplementedException ();
+               }
+#endif
+
+               [MonoTODO]
+               public void EndInit() 
+               {
+                       bInit = false;
+                       // FIXME:
+               }
+
+               public int Find(object key) 
+               {
+                       object [] keys = new object[1];
+                       keys[0] = key;
+                       return Find(keys);
+               }
+               
+               public int Find(object[] key) 
+               {
+                       int index; 
+                       if (sort == null || sort == string.Empty)
+                               throw new ArgumentException ("Find finds a row based on a Sort order, and no Sort order is specified");
+                       else {
+                               // FIXME: maybe some of those thecks could be removel.
+                               if (sortedColumns == null)
+                                       throw new Exception ("sort expression result is null");
+                               if (sortedColumns.Length == 0)
+                                       throw new Exception ("sort expression result is 0");
+                               if (sortedColumns.Length != key.Length)
+                                       throw new ArgumentException ("Expecting " + sortedColumns.Length +
+                                               " value(s) from the key being indexed, but recieved "+
+                                               key.Length+" value(s).");
+                               RowComparer rowComparer = new RowComparer (dataTable,sortedColumns);
+                               int searchResult = Array.BinarySearch (rowCache,key,rowComparer);
+                               if (searchResult < 0)
+                                       return -1;
+                               else
+                                       return searchResult;
+                       }
+               }
+               
+               [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() 
+               {
+                       return new DataViewEnumerator (rowCache);
+               }
+               #endregion // PublicMethods
+               
+               [MonoTODO]
+               [DataCategory ("Data")]
+               [DataSysDescription ("Indicates the data returned by this DataView has somehow changed.")]
+               public event ListChangedEventHandler ListChanged;
+
+               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.
+                       //              dataTable.ColumnChanged  += new DataColumnChangeEventHandler(OnColumnChanged);
+                       if (dataTable != null) {
+                               RegisterEventHandlers();
+                               UpdateIndex (true);
+                       }
+                       isOpen = true;
+               }
+               
+               private void RegisterEventHandlers()
+               {
+                       dataTable.RowChanged     += new DataRowChangeEventHandler(OnRowChanged);
+                       dataTable.RowDeleted     += new DataRowChangeEventHandler(OnRowDeleted);
+                       dataTable.Columns.CollectionChanged += new CollectionChangeEventHandler(OnColumnCollectionChanged);
+                       dataTable.Constraints.CollectionChanged += new CollectionChangeEventHandler(OnConstraintCollectionChanged);
+               }
+
+               private void UnregisterEventHandlers()
+               {
+                       dataTable.RowChanged     -= new DataRowChangeEventHandler(OnRowChanged);
+                       dataTable.RowDeleted     -= new DataRowChangeEventHandler(OnRowDeleted);
+                       dataTable.Columns.CollectionChanged -= new CollectionChangeEventHandler(OnColumnCollectionChanged);
+                       dataTable.Constraints.CollectionChanged -= new CollectionChangeEventHandler(OnConstraintCollectionChanged);
+               }
+               
+               private void OnColumnChanged(object sender, DataColumnChangeEventArgs args)
+               {       /* not used */
+                       UpdateIndex(true);
+               }
+               
+               private void OnRowChanged(object sender, DataRowChangeEventArgs args)
+               {
+                       int oldIndex,newIndex;
+                       oldIndex = newIndex = -1;
+                       oldIndex = IndexOf (args.Row);
+                       UpdateIndex (true);
+                       newIndex = IndexOf (args.Row);
+
+                       /* ItemAdded */
+                       if(args.Action == DataRowAction.Add)
+                       {       
+                               OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, newIndex, -1));
+                       }
+                               
+                       /* ItemChanged or ItemMoved */
+                       if (args.Action == DataRowAction.Change) { 
+                               if (oldIndex == newIndex)
+                               OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, newIndex, -1)); 
+                               else
+                               OnListChanged (new ListChangedEventArgs (ListChangedType.ItemMoved, newIndex, oldIndex)); 
+                       }
+               }
+               
+               private void OnRowDeleted (object sender, DataRowChangeEventArgs args)
+               {
+                       /* ItemDeleted */
+                       int newIndex;
+                       newIndex = IndexOf (args.Row);
+                       UpdateIndex (true);
+                       OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, newIndex, -1));
+               }
+               
+               private void OnColumnCollectionChanged (object sender, CollectionChangeEventArgs args)
+               {
+                       UpdateIndex (true);
+                       /* PropertyDescriptor Add */
+                       if (args.Action == CollectionChangeAction.Add)
+                               OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorAdded,0,0));
+                       /* PropertyDescriptor Removed */
+                       if (args.Action == CollectionChangeAction.Remove)
+                               OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorDeleted,0,0));
+                       /* FIXME: PropertyDescriptor Changed ???*/
+                       if (args.Action == CollectionChangeAction.Refresh)
+                               OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged,0,0));
+               }
+               private void OnConstraintCollectionChanged(object sender, CollectionChangeEventArgs args)
+               {
+                       //      The Sort variable is set to the UniqueConstraint column.
+                       //  if ApplyDefault Sort is true and Sort is null or is not set Explicitly
+                       
+                       // FIXME: The interal cache may change as result of change in Constraint collection
+                       // one such scenerio is taken care.
+                       // There may be more. I dont know what else can be done.
+                       /* useDefaultSort is set to false when Sort is set explicitly */
+                       if (args.Action == CollectionChangeAction.Add && args.Element is UniqueConstraint) {
+                               if (ApplyDefaultSort == true && useDefaultSort == true)
+                                               Sort = GetSortString ((UniqueConstraint) args.Element);
+                       }
+                       UpdateIndex (true);
+                       /* ItemReset */
+                       OnListChanged (new ListChangedEventArgs (ListChangedType.Reset,-1,-1));
+               }
+
+               // internal use by Mono
+               protected void Reset() 
+               {
+                       // TODO: what really happens?
+                       Close ();
+                       rowCache = new DataRowView[0];
+                       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 (rowFilterExpr, sortedColumns, 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 int IndexOf(DataRow dr)
+               {
+                       for (int i=0; i < rowCache.Length; i++)
+                               if (dr.Equals (rowCache [i].Row))
+                                       return i;
+                       return -1;
+               }
+               
+               private string GetSortString (UniqueConstraint uc)
+               {
+                       string sortKey = null;
+                       foreach (DataColumn dc in uc.Columns)
+                               sortKey += dc.ColumnName + ", ";
+                       sortKey = sortKey.Substring (0,sortKey.Length - 2);
+                       return sortKey;
+               }
+               
+               private object [] GetSearchKey (DataRow dr)
+               {
+                       if (sortedColumns == null) 
+                               return null;
+                       object [] keys = new object [sortedColumns.Length];
+                       int i = 0;
+                       foreach (SortableColumn sc in sortedColumns) {
+                               keys [i] = dr [sc.Column];
+                               i++;
+                       }
+                       return keys;
+               }
+
+               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;
+                       }
+               }
+               
+               private class RowComparer : IComparer 
+               {
+                       private SortableColumn [] sortColumns;
+                       private DataTable table;
+                       public RowComparer(DataTable table, SortableColumn[] sortColumns) 
+                       {
+                               this.table = table;                     
+                               this.sortColumns = sortColumns;
+                       }
+
+                       public SortableColumn[] SortedColumns {
+                               get {
+                                       return sortColumns;
+                               }
+                       }
+                       
+                       int IComparer.Compare (object x, object y) 
+                       {
+                               if(x == null)
+                                       throw new Exception ("Object to compare is null: x");
+                               if(y == null)
+                                       throw new Exception ("Object to compare is null: y");
+                               DataRowView rowView = (DataRowView) y;
+                               object [] keys = (object [])x;
+                               for(int i = 0; i < sortColumns.Length; i++) {
+                                       SortableColumn sortColumn = sortColumns [i];
+                                       DataColumn dc = sortColumn.Column;
+
+                                       IComparable row = (IComparable) rowView.Row [dc];
+                                       object key = keys [i];
+                                       
+                                       int result = CompareObjects (key,row);
+                                       if (result != 0) {
+                                               if (sortColumn.SortDirection == ListSortDirection.Ascending)
+                                                       return result;
+                                               else 
+                                                       return -result;
+                                       }
+                               }
+                               return 0;
+                       }
+
+                       private int CompareObjects (object a, object b) 
+                       {
+                               if (a == b)
+                                       return 0;
+                               else if (a == null)
+                                       return -1;
+                               else if (a == DBNull.Value)
+                                       return -1;
+                               else if (b == null)
+                                       return 1;
+                               else if (b == DBNull.Value)
+                                       return 1;
+
+                               if((a is string) && (b is string)) {
+                                       a = ((string) a).ToUpper (table.Locale);
+                                       b = ((string) b).ToUpper (table.Locale);                        
+                               }
+
+                               if (a is IComparable)
+                                       return ((a as IComparable).CompareTo (b));
+                               else if (b is IComparable)
+                                       return -((b as IComparable).CompareTo (a));
+
+                               throw new ArgumentException ("Neither a nor b IComparable");
+                       }
+               }
+
+       }
+}