2007-12-18 Carlos Alberto Cortez <calberto.cortez@gmail.com>
[mono.git] / mcs / class / System.Data / System.Data / DataView.cs
1 //\r
2 // System.Data.DataView.cs\r
3 //\r
4 // Author:\r
5 //    Daniel Morgan <danmorg@sc.rr.com>\r
6 //    Tim Coleman (tim@timcoleman.com)\r
7 //    Punit Todi (punits_mailbox@yahoo.com)\r
8 //    Atsushi Enomoto <atsushi@ximian.com>\r
9 //    Konstantin Triger (kostat@mainsoft.com)\r
10 //\r
11 // Copyright (C) Daniel Morgan, 2002, 2003\r
12 // (C) Ximian, Inc 2002\r
13 // Copyright (C) Tim Coleman, 2002-2003         \r
14 \r
15 using System;\r
16 using System.Collections;\r
17 using System.ComponentModel;\r
18 using System.Reflection;\r
19 using System.Data.Common;\r
20 using System.Globalization;\r
21 using Mono.Data.SqlExpressions;\r
22 using System.Text;\r
23 \r
24 namespace System.Data \r
25 {\r
26         /// <summary>\r
27         /// A DataView is used in the binding of data between\r
28         /// a DataTable and Windows Forms or Web Forms allowing\r
29         /// a view of a DataTable for editing, filtering,\r
30         /// navigation, searching, and sorting.\r
31         /// </summary>\r
32         //[Designer]\r
33         [Editor ("Microsoft.VSDesigner.Data.Design.DataSourceEditor, " + Consts.AssemblyMicrosoft_VSDesigner,\r
34                  "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]\r
35         [DefaultEvent ("PositionChanged")]\r
36         [DefaultProperty ("Table")]\r
37         [DesignerAttribute ("Microsoft.VSDesigner.Data.VS.DataViewDesigner, "+ Consts.AssemblyMicrosoft_VSDesigner, "System.ComponentModel.Design.IDesigner")]\r
38 #if NET_2_0\r
39         public class DataView : MarshalByValueComponent, IBindingList, IList, ICollection, IEnumerable, ITypedList, ISupportInitialize, IBindingListView, ISupportInitializeNotification\r
40 #else\r
41         public class DataView : MarshalByValueComponent, IBindingList, IList, ICollection, IEnumerable, ITypedList, ISupportInitialize\r
42 #endif\r
43         {\r
44                 internal DataTable dataTable = null;\r
45                 string rowFilter = String.Empty;\r
46                 IExpression rowFilterExpr;\r
47                 string sort = String.Empty;\r
48                 ListSortDirection [] sortOrder = null;\r
49                 PropertyDescriptor sortProperty = null;\r
50                 DataColumn [] sortColumns = null;\r
51                 internal DataViewRowState rowState;\r
52                 internal DataRowView[] rowCache = new DataRowView [0];\r
53 #if NET_2_0\r
54                 private bool dataViewInitialized = true;\r
55 #endif\r
56 \r
57                 // BeginInit() support\r
58                 bool isInitPhase = false;\r
59                 bool inEndInit = false;\r
60                 DataTable initTable;\r
61                 bool initApplyDefaultSort;\r
62                 string initSort;\r
63                 string initRowFilter;\r
64                 DataViewRowState initRowState;\r
65 \r
66                 // FIXME: what are the default values?\r
67                 bool allowNew = true; \r
68                 bool allowEdit = true;\r
69                 bool allowDelete = true;\r
70                 bool applyDefaultSort = false;\r
71                 //bool isSorted = false;\r
72 \r
73                 bool isOpen = false;\r
74 \r
75                 bool useDefaultSort = true;\r
76                 \r
77                 Index _index;\r
78                 internal DataRow _lastAdded = null;\r
79                 \r
80                 private DataViewManager dataViewManager = null;\r
81                 internal static ListChangedEventArgs ListResetEventArgs = new ListChangedEventArgs (ListChangedType.Reset,-1,-1);\r
82 \r
83                 #region Constructors\r
84 \r
85                 public DataView () \r
86                 {\r
87                         rowState = DataViewRowState.CurrentRows;\r
88                         Open ();\r
89                 }\r
90 \r
91                 public DataView (DataTable table)\r
92                         : this (table, (DataViewManager) null)\r
93                 {\r
94                 }\r
95 \r
96                 internal DataView (DataTable table, DataViewManager manager)\r
97                 {\r
98                         dataTable = table;\r
99                         rowState = DataViewRowState.CurrentRows;\r
100                         dataViewManager = manager;\r
101                         Open ();\r
102                 }\r
103 \r
104                 public DataView (DataTable table, string rowFilter,\r
105                         string sort, DataViewRowState rowState)\r
106                         : this (table, null, rowFilter, sort, rowState)\r
107                 {\r
108                 }\r
109 \r
110                 internal DataView (DataTable table, DataViewManager manager,\r
111                         string RowFilter, string Sort, DataViewRowState RowState)\r
112                 {\r
113                         dataTable = table;\r
114                         dataViewManager = manager;\r
115                         rowState = DataViewRowState.CurrentRows;\r
116                         this.RowFilter = RowFilter;\r
117                         this.Sort = Sort;\r
118                         rowState = RowState;\r
119                         Open ();\r
120                 }\r
121                 #endregion // Constructors\r
122 \r
123                 #region PublicProperties\r
124 \r
125                 [DataCategory ("Data")]\r
126 #if !NET_2_0\r
127                 [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows deletes.")]\r
128 #endif\r
129                 [DefaultValue (true)]\r
130                 public bool AllowDelete {\r
131                         get {\r
132                                 return allowDelete;\r
133                         }\r
134                         set {\r
135                                 allowDelete = value;\r
136                         }\r
137                 }\r
138 \r
139                 [DataCategory ("Data")]\r
140 #if !NET_2_0\r
141                 [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows edits.")]\r
142 #endif\r
143                 [DefaultValue (true)]\r
144                 public bool AllowEdit {\r
145                         get {\r
146                                 return allowEdit;\r
147                         }\r
148                         set {\r
149                                 allowEdit = value;\r
150                         }\r
151                 }\r
152 \r
153                 [DataCategory ("Data")]\r
154 #if !NET_2_0\r
155                 [DataSysDescription ("Indicates whether this DataView and the user interface associated with it allows new rows to be added.")]\r
156 #endif\r
157                 [DefaultValue (true)]\r
158                 public bool AllowNew {\r
159                         get {\r
160                                 return allowNew;\r
161                         }\r
162                         \r
163                         set {\r
164                                 allowNew = value;\r
165                         }\r
166                 }\r
167 \r
168                 [DataCategory ("Data")]\r
169 #if !NET_2_0\r
170                 [DataSysDescription ("Indicates whether to use the default sort if the Sort property is not set.")]\r
171 #endif\r
172                 [DefaultValue (false)]\r
173                 [RefreshProperties (RefreshProperties.All)]\r
174                 public bool ApplyDefaultSort {\r
175                         get { return applyDefaultSort; }\r
176                         set {\r
177                                 if (isInitPhase) {\r
178                                         initApplyDefaultSort = value;\r
179                                         return;\r
180                                 }\r
181                                 if (applyDefaultSort == value)\r
182                                         return;\r
183 \r
184                                 applyDefaultSort = value;\r
185                                 if (applyDefaultSort == true &&\r
186                                         (sort == null || sort == string.Empty))\r
187                                         PopulateDefaultSort ();\r
188                                 if (!inEndInit) {\r
189                                         UpdateIndex (true);\r
190                                         OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));\r
191                                 }\r
192                         }\r
193                 }\r
194                 // get the count of rows in the DataView after RowFilter \r
195                 // and RowStateFilter have been applied\r
196                 [Browsable (false)]\r
197 #if !NET_2_0\r
198                 [DataSysDescription ("Returns the number of items currently in this view.")]\r
199 #endif\r
200                 public int Count {\r
201                         get {\r
202                                 return rowCache.Length;\r
203                         }\r
204                 }\r
205 \r
206                 [Browsable (false)]\r
207 #if !NET_2_0\r
208                 [DataSysDescription ("This returns a pointer to back to the DataViewManager that owns this DataSet (if any).")]\r
209 #endif\r
210                 public DataViewManager DataViewManager {\r
211                         get {\r
212                                 return dataViewManager;\r
213                         }\r
214                 }\r
215 \r
216                 // Item indexer\r
217                 // the compiler creates a DefaultMemeberAttribute from\r
218                 // this IndexerNameAttribute\r
219                 [System.Runtime.CompilerServices.IndexerName("Item")]\r
220                 public DataRowView this[int recordIndex] {\r
221                         get {\r
222                                 if (recordIndex > rowCache.Length)\r
223                                         throw new IndexOutOfRangeException ("There is no row at " +\r
224                                                                             "position: " + recordIndex + ".");\r
225                                 return rowCache [recordIndex];\r
226                         }\r
227                 }\r
228 \r
229                 [DataCategory ("Data")]\r
230 #if !NET_2_0\r
231                 [DataSysDescription ("Indicates an expression used to filter the data returned by this DataView.")]\r
232 #endif\r
233                 [DefaultValue ("")]\r
234                 public virtual string RowFilter {\r
235                         get { return rowFilter; }\r
236                         set {\r
237                                 if (value == null)\r
238                                         value = String.Empty;\r
239                                 if (isInitPhase) {\r
240                                         initRowFilter = value;\r
241                                         return;\r
242                                 }\r
243 \r
244                                 CultureInfo info = (Table != null) ? Table.Locale : CultureInfo.CurrentCulture;\r
245                                 if (String.Compare(rowFilter, value, false, info) == 0)\r
246                                         return;\r
247 \r
248                                 if (value == String.Empty) \r
249                                         rowFilterExpr = null;\r
250                                 else {\r
251                                         Parser parser = new Parser ();\r
252                                         rowFilterExpr = parser.Compile (value);\r
253                                 }\r
254                                 rowFilter = value;\r
255                                 if (!inEndInit)\r
256                                         UpdateIndex (true);\r
257                         }\r
258                 }\r
259 \r
260                 [DataCategory ("Data")]\r
261 #if !NET_2_0\r
262                 [DataSysDescription ("Indicates the versions of data returned by this DataView.")]\r
263 #endif\r
264                 [DefaultValue (DataViewRowState.CurrentRows)]\r
265                 public DataViewRowState RowStateFilter {\r
266                         get { return rowState; }\r
267                         set {\r
268                                 if (isInitPhase) {\r
269                                         initRowState = value;\r
270                                         return;\r
271                                 }\r
272 \r
273                                 if (value == rowState)\r
274                                         return;\r
275 \r
276                                 rowState = value;\r
277                                 if (!inEndInit) {\r
278                                         UpdateIndex (true);\r
279                                         OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));\r
280                                 }\r
281                         }\r
282                 }\r
283 \r
284                 [DataCategory ("Data")]\r
285 #if !NET_2_0\r
286                 [DataSysDescription ("Indicates the order in which data is returned by this DataView.")]\r
287 #endif\r
288                 [DefaultValue ("")]\r
289                 public string Sort {\r
290                         get { \r
291                                 if (useDefaultSort)\r
292                                         return String.Empty;\r
293                                 else\r
294                                         return sort;\r
295                         }\r
296 \r
297                         set {\r
298                                 if (isInitPhase) {\r
299                                         initSort = value;\r
300                                         return;\r
301                                 }\r
302                                 if (value == sort)\r
303                                         return;\r
304 \r
305                                 if ((value == null) || (value.Equals (String.Empty))) { \r
306                                 /* if given value is null useDefaultSort */\r
307                                         useDefaultSort = true;\r
308                                         /* if ApplyDefault sort is true try appling it */\r
309                                         if (ApplyDefaultSort == true)\r
310                                                 PopulateDefaultSort ();\r
311                                 }\r
312                                 else {  \r
313                                         /* else donot useDefaultSort. set it as false */\r
314                                         /* sort is set to value specified */\r
315                                         useDefaultSort = false;\r
316                                         sort = value;\r
317                                         //sortedColumns = SortableColumn.ParseSortString (dataTable, value, true);\r
318                                 }\r
319                                 \r
320                                 if (!inEndInit) {\r
321                                         UpdateIndex (true);\r
322                                         OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));\r
323                                 }\r
324                         }\r
325                 }\r
326 \r
327                 [TypeConverter (typeof (DataTableTypeConverter))]\r
328                 [DataCategory ("Data")]\r
329 #if !NET_2_0\r
330                 [DataSysDescription ("Indicates the table this DataView uses to get data.")]\r
331 #endif\r
332                 [DefaultValue (null)]\r
333                 [RefreshProperties (RefreshProperties.All)]\r
334                 public DataTable Table {\r
335                         get { return dataTable; }\r
336                         set {\r
337                                 if (value == dataTable)\r
338                                         return;\r
339 \r
340                                 if (isInitPhase) {\r
341                                         initTable = value;\r
342                                         return;\r
343                                 }\r
344 \r
345                                 if (value != null && value.TableName.Equals("")) {\r
346                                         throw new DataException("Cannot bind to DataTable with no name.");\r
347                                 }\r
348 \r
349                                 if (dataTable != null) {\r
350                                         UnregisterEventHandlers ();\r
351                                 }\r
352 \r
353                                 dataTable = value;\r
354 \r
355                                 if (dataTable != null) {\r
356                                         RegisterEventHandlers ();\r
357                                         OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged, 0, 0));\r
358                                         sort = "";\r
359                                         rowFilter = "";\r
360                                         if (!inEndInit) {\r
361                                                 UpdateIndex (true);\r
362                                                 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1));\r
363                                         }\r
364                                 }\r
365                         }\r
366                 }\r
367 \r
368 #if NET_2_0\r
369                 [Browsable (false)]\r
370                 public bool IsInitialized {\r
371                         get { return dataViewInitialized;}\r
372                 }\r
373 #endif\r
374                 #endregion // PublicProperties\r
375                 \r
376                 #region PublicMethods\r
377 \r
378                 public virtual DataRowView AddNew() \r
379                 {\r
380                         if (!IsOpen)\r
381                                 throw new DataException ("DataView is not open.");\r
382                         if (!AllowNew)\r
383                                 throw new DataException ("Cannot call AddNew on a DataView where AllowNew is false.");\r
384                         \r
385                         if (_lastAdded != null) {\r
386                                 // FIXME : finish last added\r
387                                 CompleteLastAdded(true);\r
388                         }\r
389 \r
390                         _lastAdded = dataTable.NewRow ();\r
391                         UpdateIndex(true);\r
392                         OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, Count - 1, -1));\r
393 \r
394                         return this[Count - 1];\r
395                 }\r
396 \r
397                 internal void CompleteLastAdded(bool add)\r
398                 {\r
399                         DataRow dr = _lastAdded;\r
400 \r
401                         if (add) {\r
402                                 try {\r
403                                         dataTable.Rows.Add(_lastAdded);\r
404                                         //OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, Count - 1, -1));\r
405                                         _lastAdded = null;\r
406                                         UpdateIndex ();\r
407                                 }\r
408                                 catch(Exception e) {\r
409                                         _lastAdded = dr;\r
410                                         throw e;\r
411                                 }\r
412                         }\r
413                         else {\r
414                                 _lastAdded.CancelEdit();\r
415                                 _lastAdded = null;\r
416                                 UpdateIndex ();\r
417                                 OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, Count, -1));\r
418                         }\r
419                 }\r
420 \r
421                 public void BeginInit() \r
422                 {\r
423                         initTable = Table;\r
424                         initApplyDefaultSort = ApplyDefaultSort;\r
425                         initSort = Sort;\r
426                         initRowFilter = RowFilter;\r
427                         initRowState = RowStateFilter;\r
428 \r
429                         isInitPhase = true;\r
430 #if NET_2_0\r
431                         dataViewInitialized = false;\r
432 #endif\r
433                 }\r
434 \r
435                 public void CopyTo (Array array, int index) \r
436                 {\r
437                         if (index + rowCache.Length > array.Length) {\r
438                                 throw new IndexOutOfRangeException();\r
439                         }\r
440 \r
441                         int row = 0;\r
442                         for (; row < rowCache.Length && row < array.Length; row++) {\r
443                                 array.SetValue (rowCache[row], index + row);\r
444                         }\r
445                 }\r
446 \r
447                 public void Delete(int index) \r
448                 {\r
449                         if (!IsOpen)\r
450                                 throw new DataException ("DataView is not open.");\r
451 \r
452                         if (_lastAdded != null && index == Count) {\r
453                                 CompleteLastAdded(false);\r
454                                 return;\r
455                         }\r
456 \r
457                         if (!AllowDelete)\r
458                                 throw new DataException ("Cannot delete on a DataSource where AllowDelete is false.");\r
459                         \r
460                         if (index > rowCache.Length)\r
461                                 throw new IndexOutOfRangeException ("There is no row at " +\r
462                                                 "position: " + index + ".");\r
463                         DataRowView row = rowCache [index];\r
464                         row.Row.Delete();\r
465                 }\r
466 \r
467 #if NET_2_0\r
468                 public virtual bool Equals (DataView dv)\r
469                 {\r
470                         if (this == dv)\r
471                                 return true;\r
472                         if (!(this.Table == dv.Table && this.Sort == dv.Sort &&\r
473                                 this.RowFilter == dv.RowFilter && \r
474                                 this.RowStateFilter == dv.RowStateFilter &&\r
475                                 this.AllowEdit == dv.AllowEdit && \r
476                                 this.AllowNew == dv.AllowNew &&\r
477                                 this.AllowDelete == dv.AllowDelete &&\r
478                                 this.Count == dv.Count))\r
479                                 return false;\r
480 \r
481                         for (int i=0; i < Count; ++i)\r
482                                 if (!this [i].Equals (dv [i]))\r
483                                         return false;\r
484                         return true;\r
485                 }\r
486 #endif\r
487 \r
488                 public void EndInit() \r
489                 {\r
490                         isInitPhase = false;\r
491 \r
492                         inEndInit = true;\r
493 \r
494                         Table = initTable;\r
495                         ApplyDefaultSort = initApplyDefaultSort;\r
496                         Sort = initSort;\r
497                         RowFilter = initRowFilter;\r
498                         RowStateFilter = initRowState;\r
499 \r
500                         inEndInit = false;\r
501 \r
502                         UpdateIndex (true);\r
503 \r
504 #if NET_2_0\r
505                         dataViewInitialized = true;\r
506                         DataViewInitialized ();\r
507 #endif\r
508                 }\r
509 \r
510                 public int Find(object key) \r
511                 {\r
512                         object [] keys = new object[] { key };\r
513                         return Find(keys);\r
514                 }\r
515                 \r
516                 public int Find(object[] keys) \r
517                 {\r
518                         if (sort == null || sort == string.Empty) {\r
519                                 throw new ArgumentException ("Find finds a row based on a Sort order, and no Sort order is specified");\r
520                         }\r
521 \r
522                         if (Index == null) {\r
523                                 UpdateIndex(true);\r
524                         }\r
525 \r
526                         int index = -1;                                 \r
527                         try {\r
528                                 index = Index.FindIndex(keys);\r
529                         }\r
530                         catch(FormatException) {\r
531                                 // suppress exception\r
532                         }\r
533                         catch(InvalidCastException) {\r
534                                 // suppress exception\r
535                         }\r
536                         return index;\r
537                 }\r
538                 \r
539                 public DataRowView[] FindRows(object key) \r
540                 {\r
541                         return FindRows(new object[] {key});\r
542                 }\r
543 \r
544                 public DataRowView[] FindRows(object[] keys) \r
545                 {\r
546                         if (sort == null || sort == string.Empty) {\r
547                                 throw new ArgumentException ("Find finds a row based on a Sort order, and no Sort order is specified");\r
548                         }\r
549 \r
550                         if (Index == null) {\r
551                                 UpdateIndex(true);\r
552                         }\r
553 \r
554                         int[] indexes = Index.FindAllIndexes(keys);\r
555 \r
556                         DataRowView[] rowViewArr = new DataRowView[indexes.Length];                     \r
557                         for (int r = 0; r < indexes.Length; r++) {\r
558                                 rowViewArr[r] = rowCache[indexes[r]];\r
559                         }\r
560                         return rowViewArr;\r
561                 }\r
562 \r
563                 public IEnumerator GetEnumerator() \r
564                 {\r
565                         DataRowView[] dataRowViews = new DataRowView[Count];\r
566                         CopyTo(dataRowViews,0);\r
567                         return dataRowViews.GetEnumerator();\r
568                 }\r
569 \r
570                 #endregion // PublicMethods\r
571                 \r
572                 [DataCategory ("Data")]\r
573 #if !NET_2_0\r
574                 [DataSysDescription ("Indicates that the data returned by this DataView has somehow changed.")]\r
575 #endif\r
576                 public event ListChangedEventHandler ListChanged;\r
577 \r
578 #if NET_2_0\r
579                 public event EventHandler Initialized;\r
580 #endif\r
581 \r
582                 [Browsable (false)]\r
583 #if !NET_2_0\r
584                 [DataSysDescription ("Indicates whether the view is open.  ")]\r
585 #endif\r
586                 protected bool IsOpen {\r
587                         get { return isOpen; }\r
588                 }\r
589 \r
590                 internal Index Index\r
591                 {\r
592                         get {\r
593                                 return _index;\r
594                         }\r
595 \r
596                         set {\r
597                                 if (_index != null) {\r
598                                         _index.RemoveRef();\r
599                                         Table.DropIndex(_index);\r
600                                 }\r
601 \r
602                                 _index = value;\r
603 \r
604                                 if (_index != null) {\r
605                                         _index.AddRef();\r
606                                 }\r
607                         }\r
608                 }\r
609 \r
610                 protected void Close ()\r
611                 {\r
612                         if (dataTable != null)\r
613                                 UnregisterEventHandlers ();\r
614                         Index = null;\r
615                         rowCache = new DataRowView [0];\r
616                         isOpen = false;\r
617                 }\r
618 \r
619                 protected override void Dispose (bool disposing)\r
620                 {\r
621                         if (disposing)\r
622                                 Close ();\r
623 \r
624                         base.Dispose (disposing);\r
625                 }\r
626 \r
627                 protected virtual void IndexListChanged (\r
628                         object sender, ListChangedEventArgs e)\r
629                 {\r
630                 }\r
631 \r
632                 protected virtual void OnListChanged(ListChangedEventArgs e) \r
633                 {\r
634                         // Yes, under MS.NET, when it is overriden, the \r
635                         // events are not fired (even if it is essential\r
636                         // to internal processing).\r
637                         try {\r
638                         if (ListChanged != null)\r
639                                 ListChanged (this, e);\r
640                         } catch {\r
641                         }\r
642                 }\r
643 \r
644                 internal void ChangedList(ListChangedType listChangedType, int newIndex,int oldIndex)\r
645                 {\r
646                         ListChangedEventArgs e = new ListChangedEventArgs(listChangedType,newIndex,oldIndex);\r
647                         OnListChanged(e);\r
648                 }\r
649 \r
650                 protected void Open() \r
651                 {\r
652                         // I wonder if this comment is still valid, but keep\r
653                         // in the meantime.\r
654 \r
655                         // FIXME: create the initial index cache to the DataTable, and \r
656                         //        only refresh the index when the DataTable\r
657                         //        has changes via column, row, or constraint\r
658                         //        changed events. the index cache is generally\r
659                         //        a DataViewRow array that points to the actual\r
660                         //        DataRows in the this DataTable's DataRowCollection;\r
661                         //        this index is really a cache that gets \r
662                         //        created during Open(), gets Updated \r
663                         //        when various properties of this view\r
664                         //        changes, gets Updated when this DataTable's \r
665                         //        row, column, or constraint collections have changed.\r
666                         //        I'm not sure what else.\r
667                         //        The data view will know one of the DataTable's\r
668                         //        collections have changed via one of \r
669                         //        its changed events.\r
670                         //        Otherwise, if getting a/the DataRowView(s),\r
671                         //        Count, or other properties, then just use the\r
672                         //        index cache.\r
673                         //              dataTable.ColumnChanged  += new DataColumnChangeEventHandler(OnColumnChanged);\r
674                         \r
675                         UpdateIndex (true);\r
676                         if (dataTable != null) {\r
677                                 RegisterEventHandlers();\r
678                         }\r
679                         isOpen = true;\r
680                 }\r
681                 \r
682                 private void RegisterEventHandlers()\r
683                 {\r
684                         //dataTable.ColumnChanging += new DataColumnChangeEventHandler(OnColumnChanging);\r
685                         dataTable.ColumnChanged  += new DataColumnChangeEventHandler(OnColumnChanged);\r
686                         dataTable.RowChanged     += new DataRowChangeEventHandler(OnRowChanged);\r
687                         //dataTable.RowDeleting    += new DataRowChangeEventHandler(OnRowDeleting);\r
688                         dataTable.RowDeleted     += new DataRowChangeEventHandler(OnRowDeleted);\r
689                         dataTable.Columns.CollectionChanged += new CollectionChangeEventHandler(ColumnCollectionChanged);\r
690                         dataTable.Columns.CollectionMetaDataChanged += new CollectionChangeEventHandler(ColumnCollectionChanged);\r
691                         dataTable.Constraints.CollectionChanged += new CollectionChangeEventHandler(OnConstraintCollectionChanged);\r
692                         dataTable.ChildRelations.CollectionChanged += new CollectionChangeEventHandler(OnRelationCollectionChanged);\r
693                         dataTable.ParentRelations.CollectionChanged += new CollectionChangeEventHandler(OnRelationCollectionChanged);\r
694 \r
695                         dataTable.Rows.ListChanged += new ListChangedEventHandler (OnRowCollectionChanged);\r
696                 }\r
697                 \r
698                 private void OnRowCollectionChanged (object sender, ListChangedEventArgs args)\r
699                 {\r
700                         if (args.ListChangedType == ListChangedType.Reset) {\r
701                                 rowCache = new DataRowView [0];\r
702                                 UpdateIndex (true);\r
703                                 OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1 ));\r
704                         }\r
705                 }\r
706 \r
707                 private void UnregisterEventHandlers()\r
708                 {\r
709 //                      dataTable.ColumnChanging -= new DataColumnChangeEventHandler(OnColumnChanging);\r
710                         dataTable.ColumnChanged  -= new DataColumnChangeEventHandler(OnColumnChanged);\r
711                         dataTable.RowChanged     -= new DataRowChangeEventHandler(OnRowChanged);\r
712 //                      dataTable.RowDeleting    -= new DataRowChangeEventHandler(OnRowDeleting);\r
713                         dataTable.RowDeleted     -= new DataRowChangeEventHandler(OnRowDeleted);\r
714                         dataTable.Columns.CollectionChanged -= new CollectionChangeEventHandler(ColumnCollectionChanged);\r
715                         dataTable.Columns.CollectionMetaDataChanged -= new CollectionChangeEventHandler(ColumnCollectionChanged);\r
716                         dataTable.Constraints.CollectionChanged -= new CollectionChangeEventHandler(OnConstraintCollectionChanged);\r
717                         dataTable.ChildRelations.CollectionChanged -= new CollectionChangeEventHandler(OnRelationCollectionChanged);\r
718                         dataTable.ParentRelations.CollectionChanged -= new CollectionChangeEventHandler(OnRelationCollectionChanged);\r
719 \r
720                         dataTable.Rows.ListChanged -= new ListChangedEventHandler (OnRowCollectionChanged);\r
721                 }\r
722 \r
723                 // These index storing and rowView preservation must be done\r
724                 // before the actual row value is changed; thus we can't use\r
725                 // RowChanging which accepts "already modified" DataRow.\r
726 \r
727                 private void OnColumnChanged(object sender, DataColumnChangeEventArgs args)\r
728                 {       /* not used */\r
729                         //UpdateIndex(true);\r
730                 }\r
731                 \r
732                 private void OnRowChanged(object sender, DataRowChangeEventArgs args)\r
733                 {\r
734                         int oldIndex,newIndex;\r
735                         oldIndex = newIndex = -1;\r
736                         oldIndex = IndexOf (args.Row);\r
737                         UpdateIndex (true);\r
738                         newIndex = IndexOf (args.Row);\r
739 \r
740                         /* ItemAdded */\r
741                         if(args.Action == DataRowAction.Add)\r
742                         {\r
743                                 OnListChanged (new ListChangedEventArgs (ListChangedType.ItemAdded, newIndex, -1));\r
744                         }\r
745                                 \r
746                         /* ItemChanged or ItemMoved */\r
747                         if (args.Action == DataRowAction.Change) {\r
748                                 if (oldIndex == newIndex)\r
749                                         OnListChanged (new ListChangedEventArgs (ListChangedType.ItemChanged, newIndex, -1));\r
750                                 else\r
751                                         OnListChanged (new ListChangedEventArgs (ListChangedType.ItemMoved, newIndex, oldIndex));\r
752                         }\r
753                 }\r
754 \r
755                 private void OnRowDeleted (object sender, DataRowChangeEventArgs args)\r
756                 {\r
757                         /* ItemDeleted */\r
758                         int newIndex;\r
759                         newIndex = IndexOf (args.Row);\r
760                         UpdateIndex (true);\r
761                         OnListChanged (new ListChangedEventArgs (ListChangedType.ItemDeleted, newIndex, -1));\r
762                 }\r
763                 \r
764 #if NET_2_0\r
765                 private void DataViewInitialized ()\r
766                 {\r
767                         EventArgs e = new EventArgs ();\r
768                         OnDataViewInitialized (e);\r
769                 }\r
770 \r
771                 private void OnDataViewInitialized (EventArgs e) {\r
772                         if (null != Initialized) {\r
773                                 Initialized (this, e);\r
774                         }\r
775                 }\r
776 #endif\r
777                 protected virtual void ColumnCollectionChanged (object sender, CollectionChangeEventArgs args)\r
778                 {\r
779                         // UpdateIndex() is not invoked here (even if the sort\r
780                         // column is being removed).\r
781 \r
782                         /* PropertyDescriptor Add */\r
783                         if (args.Action == CollectionChangeAction.Add)\r
784                                 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorAdded,0,0));\r
785                         /* PropertyDescriptor Removed */\r
786                         if (args.Action == CollectionChangeAction.Remove)\r
787                                 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorDeleted,0,0));\r
788                         /* PropertyDescriptor Changed, comes from DataColumnCollection.CollectionMetaDataChanged */\r
789                         if (args.Action == CollectionChangeAction.Refresh)\r
790                                 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged,0,0));\r
791                 }\r
792 \r
793                 private void OnConstraintCollectionChanged(object sender, CollectionChangeEventArgs args)\r
794                 {\r
795                         //      The Sort variable is set to the UniqueConstraint column.\r
796                         //  if ApplyDefault Sort is true and Sort is null or is not set Explicitly\r
797                         \r
798                         // FIXME: The interal cache may change as result of change in Constraint collection\r
799                         // one such scenerio is taken care.\r
800                         // There may be more. I dont know what else can be done.\r
801                         /* useDefaultSort is set to false when Sort is set explicitly */\r
802                         if (args.Action == CollectionChangeAction.Add && args.Element is UniqueConstraint) {\r
803                                 if (ApplyDefaultSort == true && useDefaultSort == true)\r
804                                         PopulateDefaultSort ((UniqueConstraint) args.Element);\r
805                         }\r
806                         // UpdateIndex() is not invoked here.\r
807                 }\r
808 \r
809                 private void OnRelationCollectionChanged(object sender, CollectionChangeEventArgs args)\r
810                 {\r
811                         /* PropertyDescriptor Add */\r
812                         if (args.Action == CollectionChangeAction.Add)\r
813                                 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorAdded,0,0));\r
814                         /* PropertyDescriptor Removed */\r
815                         if (args.Action == CollectionChangeAction.Remove)\r
816                                 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorDeleted,0,0));\r
817                         /* FIXME: PropertyDescriptor Changed ???*/\r
818                         if (args.Action == CollectionChangeAction.Refresh)\r
819                                 OnListChanged (new ListChangedEventArgs (ListChangedType.PropertyDescriptorChanged,0,0));\r
820                 }\r
821 \r
822                 // internal use by Mono\r
823                 protected void Reset() \r
824                 {\r
825                         // TODO: what really happens?\r
826                         Close ();\r
827                         rowCache = new DataRowView [0];\r
828                         Open ();\r
829                         OnListChanged (new ListChangedEventArgs (ListChangedType.Reset, -1, -1 ));\r
830                 }\r
831 \r
832 #if NET_2_0\r
833                 public DataTable ToTable ()\r
834                 {\r
835                         return this.ToTable (Table.TableName, false, new string[] {});\r
836                 }\r
837 \r
838                 public DataTable ToTable (string tableName)\r
839                 {\r
840                         return this.ToTable (tableName, false, new string[] {});\r
841                 }\r
842 \r
843                 public DataTable ToTable (bool isDistinct, params string[] columnNames)\r
844                 {\r
845                         return this.ToTable (Table.TableName, isDistinct, columnNames);\r
846                 }\r
847                 \r
848                 public DataTable ToTable (string tablename, bool isDistinct, params string[] columnNames)\r
849                 {\r
850                         if (columnNames == null)\r
851                                 throw new ArgumentNullException ("columnNames", "'columnNames' argument cannot be null.");\r
852  \r
853                         DataTable newTable = new DataTable (tablename);\r
854 \r
855                         DataColumn[] columns;\r
856                         ListSortDirection[] sortDirection = null;\r
857                         if (columnNames.Length != 0) {\r
858                                 columns = new DataColumn [columnNames.Length];\r
859                                 for (int i=0; i < columnNames.Length; ++i)\r
860                                         columns [i] = Table.Columns [columnNames [i]];\r
861 \r
862                                 if (sortColumns != null) {\r
863                                         sortDirection = new ListSortDirection [columnNames.Length];\r
864                                         for (int i=0; i < columnNames.Length; ++i) {\r
865                                                 sortDirection [i] = ListSortDirection.Ascending;\r
866                                                 for (int j=0; j < sortColumns.Length; ++j) {\r
867                                                         if (sortColumns [j] != columns [i])\r
868                                                                 continue;\r
869                                                         sortDirection [i] = sortOrder [j];\r
870                                                 }\r
871                                         }\r
872                                 }\r
873                         } else {\r
874                                 columns = (DataColumn[]) Table.Columns.ToArray (typeof (DataColumn));\r
875                                 sortDirection = sortOrder;\r
876                         }\r
877 \r
878                         ArrayList expressionCols = new ArrayList ();\r
879                         for (int i=0; i < columns.Length; ++i) {\r
880                                 DataColumn col = columns [i].Clone ();\r
881                                 if (col.Expression != String.Empty) { \r
882                                         col.Expression = "";\r
883                                         expressionCols.Add (col);\r
884                                 }\r
885                                 if (col.ReadOnly)\r
886                                         col.ReadOnly = false;\r
887                                 newTable.Columns.Add (col);\r
888                         }\r
889 \r
890                         DataRow [] rows;\r
891                         Index index = new Index (new Key(Table, columns, sortDirection, RowStateFilter, rowFilterExpr));\r
892                         if (isDistinct)\r
893                                 rows = index.GetDistinctRows ();\r
894                         else\r
895                                 rows = index.GetAllRows (); \r
896 \r
897                         foreach (DataRow row in rows) {\r
898                                 DataRow newRow = newTable.NewNotInitializedRow ();\r
899                                 newTable.Rows.AddInternal (newRow);\r
900                                 newRow.Original = -1;\r
901                                 if (row.HasVersion (DataRowVersion.Current))\r
902                                         newRow.Current = newTable.RecordCache.CopyRecord (Table, row.Current, -1);\r
903                                 else if (row.HasVersion (DataRowVersion.Original))\r
904                                         newRow.Current = newTable.RecordCache.CopyRecord (Table, row.Original, -1);\r
905 \r
906                                 foreach (DataColumn col in expressionCols)\r
907                                         newRow [col] = row [col.ColumnName];\r
908                                 newRow.Original = -1;\r
909                         }\r
910                         return newTable;\r
911                 }\r
912 #endif\r
913                 protected void UpdateIndex() \r
914                 {\r
915                         UpdateIndex(false);\r
916                 }\r
917 \r
918                 // This is method is internal to \r
919                 // the Mono implementation of DataView; it\r
920                 // is not to be used from your code.\r
921                 //\r
922                 // Update the DataRowView array which is an index cache\r
923                 // into the DataTable's DataRowCollection.\r
924                 //\r
925                 // I assume this is what UpdateIndex is used for\r
926                 protected virtual void UpdateIndex(bool force) \r
927                 {\r
928                         if (Table == null) {\r
929                                 // FIXME\r
930                                 return;\r
931                         }\r
932 \r
933                         if (Index == null || force) {\r
934                                 sortColumns = DataTable.ParseSortString(Table, Sort, out sortOrder, false);\r
935                                 Index = dataTable.GetIndex(sortColumns,sortOrder,RowStateFilter,FilterExpression,true);\r
936                         }\r
937                         else {\r
938                                 Index.Key.RowStateFilter = RowStateFilter;\r
939                                 Index.Reset();\r
940                         }\r
941 \r
942                         int[] records = Index.GetAll();\r
943 \r
944                         if (records != null) {\r
945                                 InitDataRowViewArray(records,Index.Size);\r
946                         }\r
947                         else {\r
948                                 rowCache = new DataRowView[0];\r
949                         }\r
950                 }\r
951 \r
952                 internal virtual IExpression FilterExpression\r
953                 {\r
954                         get {\r
955                                 return rowFilterExpr;\r
956                         }\r
957                 }\r
958 \r
959                 private void InitDataRowViewArray(int[] records,int size) \r
960                 {\r
961                         if (_lastAdded != null) {\r
962                                 rowCache = new DataRowView[size + 1];   \r
963                         }\r
964                         else {\r
965                                 rowCache = new DataRowView[size];                       \r
966                         }\r
967 \r
968                         for (int r = 0; r < size; r++) {\r
969                                 rowCache[r] = new DataRowView (this, Table.RecordCache[records[r]],r);\r
970                         }\r
971 \r
972                         if(_lastAdded != null) {\r
973                                 rowCache[size] = new DataRowView(this,_lastAdded,size);\r
974                         }\r
975                 }\r
976 \r
977                 PropertyDescriptorCollection ITypedList.GetItemProperties (PropertyDescriptor[] listAccessors) \r
978                 {\r
979                         if (dataTable == null)\r
980                                 return new PropertyDescriptorCollection (new PropertyDescriptor[0]);\r
981 \r
982                         // FIXME: use listAccessors somehow\r
983                         PropertyDescriptor [] descriptors = \r
984                                 new PropertyDescriptor [dataTable.Columns.Count + dataTable.ChildRelations.Count];\r
985 \r
986                         int d = 0;\r
987                         for (int col = 0; col < dataTable.Columns.Count; col ++) {\r
988                                 DataColumn dataColumn = dataTable.Columns[col];\r
989                                 DataColumnPropertyDescriptor descriptor;\r
990 \r
991                                 descriptor = new DataColumnPropertyDescriptor(\r
992                                         dataColumn.ColumnName, col, null);\r
993                                 descriptor.SetComponentType (typeof (System.Data.DataRowView));\r
994                                 descriptor.SetPropertyType (dataColumn.DataType);\r
995                                 descriptor.SetReadOnly (dataColumn.ReadOnly);\r
996                                 descriptors [d++] = descriptor;\r
997                         }\r
998                         for (int rel = 0; rel < dataTable.ChildRelations.Count; rel ++) {\r
999                                 DataRelation dataRelation = dataTable.ChildRelations[rel];\r
1000                                 DataRelationPropertyDescriptor descriptor;\r
1001 \r
1002                                 descriptor = new DataRelationPropertyDescriptor(dataRelation);\r
1003                                 descriptors [d++] = descriptor;\r
1004                         }\r
1005 \r
1006                         return new PropertyDescriptorCollection (descriptors);\r
1007                 }\r
1008 \r
1009                 \r
1010                 string ITypedList.GetListName (PropertyDescriptor[] listAccessors) \r
1011                 {\r
1012                         if (dataTable != null) {                                \r
1013                                 return dataTable.TableName;\r
1014                         }\r
1015                         return "";\r
1016                 }\r
1017 \r
1018                 bool ICollection.IsSynchronized { \r
1019                         get {\r
1020                                 return false;\r
1021                         } \r
1022                 }\r
1023 \r
1024                 object ICollection.SyncRoot { \r
1025                         get {\r
1026                                 return this;\r
1027                         }\r
1028                 }\r
1029 \r
1030                 bool IList.IsFixedSize {\r
1031                         get {\r
1032                                 return false;\r
1033                         }\r
1034                 }\r
1035                 \r
1036                 bool IList.IsReadOnly {\r
1037                         get {\r
1038                                 return false;\r
1039                         }\r
1040                 }\r
1041 \r
1042                 object IList.this[int recordIndex] {\r
1043                         get {\r
1044                                 return this[recordIndex];\r
1045                         }\r
1046 \r
1047                         [MonoTODO]\r
1048                         set{\r
1049                                 throw new InvalidOperationException();\r
1050                         }\r
1051                 }\r
1052 \r
1053                 int IList.Add (object value) \r
1054                 {\r
1055                         throw new ArgumentException ("Cannot add external objects to this list.");\r
1056                 }\r
1057 \r
1058                 void IList.Clear () \r
1059                 {\r
1060                         throw new ArgumentException ("Cannot clear this list.");\r
1061                 }\r
1062 \r
1063                 bool IList.Contains (object value) \r
1064                 {\r
1065                         DataRowView drv = value as DataRowView;\r
1066                         if (drv == null)\r
1067                                 return false;\r
1068 \r
1069                         return drv.DataView == this;\r
1070                 }\r
1071 \r
1072                 int IList.IndexOf (object value) \r
1073                 {\r
1074                         DataRowView drv = value as DataRowView;\r
1075                         if (drv != null && drv.DataView == this) {\r
1076                                 return drv.Index;\r
1077                         }\r
1078 \r
1079                         return -1;\r
1080                 }\r
1081 \r
1082                 void IList.Insert(int index,object value) \r
1083                 {\r
1084                         throw new ArgumentException ("Cannot insert external objects to this list.");\r
1085                 }\r
1086 \r
1087                 void IList.Remove(object value) \r
1088                 {\r
1089                         DataRowView drv = value as DataRowView;\r
1090                         if (drv != null && drv.DataView == this) {\r
1091                                 ((IList)this).RemoveAt(drv.Index);\r
1092                         }\r
1093 \r
1094                         throw new ArgumentException ("Cannot remove external objects to this list.");\r
1095                 }\r
1096 \r
1097                 void IList.RemoveAt(int index) \r
1098                 {\r
1099                         Delete(index);\r
1100                 }\r
1101 \r
1102                 #region IBindingList implementation\r
1103 \r
1104                 [MonoTODO]\r
1105                 void IBindingList.AddIndex (PropertyDescriptor property) \r
1106                 {\r
1107                         throw new NotImplementedException ();\r
1108                 }\r
1109 \r
1110                 object IBindingList.AddNew () \r
1111                 {\r
1112                         return this.AddNew ();\r
1113                 }\r
1114 \r
1115                 void IBindingList.ApplySort (PropertyDescriptor property, ListSortDirection direction) \r
1116                 {\r
1117                         if (! (property is DataColumnPropertyDescriptor))\r
1118                                 throw new ArgumentException ("Dataview accepts only DataColumnPropertyDescriptors", "property");\r
1119                         sortProperty = property;\r
1120                         string sort = String.Format ("[{0}]" , property.Name);\r
1121                         if (direction == ListSortDirection.Descending)\r
1122                                 sort += " DESC";\r
1123                         this.Sort = sort;\r
1124                 }\r
1125 \r
1126                 int IBindingList.Find (PropertyDescriptor property, object key) \r
1127                 {\r
1128                         DataColumn dc = Table.Columns [property.Name];\r
1129                         Index index = Table.FindIndex (new DataColumn [] {dc}, sortOrder, RowStateFilter, FilterExpression);\r
1130                         if (index == null)\r
1131                                 index = new Index (new Key (Table, new DataColumn [] {dc}, sortOrder, RowStateFilter, FilterExpression));\r
1132                         \r
1133                         return index.FindIndex (new object [] {key});\r
1134                 }\r
1135                 \r
1136                 [MonoTODO]\r
1137                 void IBindingList.RemoveIndex (PropertyDescriptor property) \r
1138                 {\r
1139                         throw new NotImplementedException ();\r
1140                 }\r
1141 \r
1142                 void IBindingList.RemoveSort () \r
1143                 {\r
1144                         sortProperty = null;\r
1145                         this.Sort = String.Empty;\r
1146                 }\r
1147                 \r
1148                 bool IBindingList.AllowEdit {\r
1149                         get { return AllowEdit; }\r
1150                 }\r
1151 \r
1152                 bool IBindingList.AllowNew {\r
1153                         get { return AllowNew; }\r
1154                 }\r
1155 \r
1156                 bool IBindingList.AllowRemove {\r
1157                         [MonoTODO]\r
1158                         get { return AllowDelete; }\r
1159                 }\r
1160 \r
1161                 bool IBindingList.IsSorted {\r
1162                         get { return (Sort != null && Sort != String.Empty); }\r
1163                 }\r
1164 \r
1165                 ListSortDirection IBindingList.SortDirection {\r
1166                         get {\r
1167                                 if (sortOrder != null && sortOrder.Length > 0)\r
1168                                         return sortOrder [0];\r
1169                                 return ListSortDirection.Ascending;\r
1170                         }\r
1171                 }\r
1172 \r
1173                 PropertyDescriptor IBindingList.SortProperty {\r
1174                         get {\r
1175                                 if (sortProperty == null && sortColumns != null && sortColumns.Length > 0) {\r
1176                                         // return property from Sort String\r
1177                                         PropertyDescriptorCollection properties = ((ITypedList)this).GetItemProperties (null);\r
1178                                         return properties.Find (sortColumns [0].ColumnName, false);\r
1179                                 }\r
1180                                 return sortProperty;\r
1181                         }\r
1182                 }\r
1183 \r
1184                 bool IBindingList.SupportsChangeNotification {\r
1185                         get { return true; }\r
1186                 }\r
1187 \r
1188                 bool IBindingList.SupportsSearching {\r
1189                         get { return true; }\r
1190                 }\r
1191 \r
1192                 bool IBindingList.SupportsSorting {\r
1193                         get { return true; }\r
1194                 }\r
1195                 \r
1196                 #endregion // IBindingList implementation\r
1197 \r
1198 #if NET_2_0\r
1199                 #region IBindingListView implementation\r
1200                 string IBindingListView.Filter {\r
1201                         get { return ((DataView)this).RowFilter; }\r
1202                         set { ((DataView)this).RowFilter = value; }\r
1203                 }\r
1204 \r
1205                 ListSortDescriptionCollection IBindingListView.SortDescriptions {\r
1206                         get {\r
1207                                 ListSortDescriptionCollection col = new ListSortDescriptionCollection ();\r
1208                                 for (int i=0; i < sortColumns.Length; ++i) {\r
1209                                         ListSortDescription ldesc = new ListSortDescription (\r
1210                                                                                 new DataColumnPropertyDescriptor (sortColumns [i]),\r
1211                                                                                 sortOrder [i]);\r
1212                                         ((IList)col).Add (ldesc);\r
1213                                 }\r
1214                                 return col;\r
1215                         }\r
1216                 }\r
1217 \r
1218                 bool IBindingListView.SupportsAdvancedSorting {\r
1219                         get { return true; }\r
1220                 }\r
1221 \r
1222                 bool IBindingListView.SupportsFiltering {\r
1223                         get { return true; }\r
1224                 }       \r
1225 \r
1226                 [MonoTODO]\r
1227                 void IBindingListView.ApplySort (ListSortDescriptionCollection sorts)\r
1228                 {\r
1229                         StringBuilder sb = new StringBuilder ();\r
1230                         foreach (ListSortDescription ldesc in sorts)\r
1231                                 sb.AppendFormat ("[{0}]{1},", ldesc.PropertyDescriptor.Name,\r
1232                                         (ldesc.SortDirection == ListSortDirection.Descending ? " DESC" : ""));\r
1233                         this.Sort = sb.ToString (0, sb.Length-1);\r
1234                 }\r
1235 \r
1236                 void IBindingListView.RemoveFilter ()\r
1237                 {\r
1238                         ((IBindingListView)this).Filter = "";\r
1239                 }\r
1240                 \r
1241                 #endregion //IBindingViewList implementation\r
1242 #endif\r
1243 \r
1244                 private int IndexOf(DataRow dr)\r
1245                 {\r
1246                         for (int i=0; i < rowCache.Length; i++)\r
1247                                 if (dr.Equals (rowCache [i].Row))\r
1248                                 return i;\r
1249                         return -1;\r
1250                 }\r
1251                 \r
1252                 private void PopulateDefaultSort () {\r
1253                         sort = "";\r
1254                         foreach (Constraint c in dataTable.Constraints) {\r
1255                                 if (c is UniqueConstraint) {\r
1256                                         PopulateDefaultSort ((UniqueConstraint) c);\r
1257                                         break;\r
1258                                 }\r
1259                         }\r
1260                 }\r
1261 \r
1262                 private void PopulateDefaultSort (UniqueConstraint uc) {\r
1263                         if (isInitPhase)\r
1264                                 return;\r
1265 \r
1266                         DataColumn[] columns = uc.Columns;\r
1267                         if (columns.Length == 0) {\r
1268                                 sort = String.Empty;\r
1269                                 return;\r
1270                         }\r
1271 \r
1272                         StringBuilder builder = new StringBuilder();\r
1273                         builder.Append(columns[0].ColumnName);\r
1274                         for (int i = 1; i<columns.Length; i++) {\r
1275                                 builder.Append(", ");\r
1276                                 builder.Append(columns[i].ColumnName);\r
1277                         }\r
1278                         sort = builder.ToString();\r
1279                 }\r
1280                 \r
1281                 internal DataView CreateChildView (DataRelation relation, int index)\r
1282                 {\r
1283                         if (relation == null || relation.ParentTable != Table) {\r
1284                                 throw new ArgumentException("The relation is not parented to the table to which this DataView points.");\r
1285                         }\r
1286 \r
1287                         int record = GetRecord(index);\r
1288                         object[] keyValues = new object[relation.ParentColumns.Length];\r
1289                         for(int i=0; i < relation.ParentColumns.Length; i++)\r
1290                                 keyValues [i] = relation.ParentColumns [i][record];\r
1291 \r
1292                         return new RelatedDataView(relation.ChildColumns,keyValues);\r
1293                 }\r
1294 \r
1295                 private int GetRecord(int index) {\r
1296                         if (index < 0 || index >= Count)\r
1297                                 throw new IndexOutOfRangeException(String.Format("There is no row at position {0}.", index));\r
1298 \r
1299                         return(index == Index.Size) ?\r
1300                                 _lastAdded.IndexFromVersion(DataRowVersion.Default) :\r
1301                                 Index.IndexToRecord(index);\r
1302                 }\r
1303 \r
1304                 internal DataRowVersion GetRowVersion(int index) {\r
1305                         int record = GetRecord(index);\r
1306                         return Table.RecordCache[record].VersionFromIndex(record);\r
1307                 }\r
1308         }\r
1309 }\r