DataView.cs 68 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768
  1. //------------------------------------------------------------------------------
  2. // <copyright file="DataView.cs" company="Microsoft">
  3. // Copyright (c) Microsoft Corporation. All rights reserved.
  4. // </copyright>
  5. // <owner current="true" primary="true">[....]</owner>
  6. // <owner current="true" primary="false">[....]</owner>
  7. //------------------------------------------------------------------------------
  8. namespace System.Data {
  9. using System;
  10. using System.Diagnostics;
  11. using System.Collections;
  12. using System.Collections.Generic;
  13. using System.ComponentModel;
  14. using System.Globalization;
  15. using System.Text;
  16. /// <devdoc>
  17. /// <para>
  18. /// Represents a databindable, customized view of a <see cref='System.Data.DataTable'/>
  19. /// for sorting, filtering, searching, editing, and navigation.
  20. /// </para>
  21. /// </devdoc>
  22. [
  23. Designer("Microsoft.VSDesigner.Data.VS.DataViewDesigner, " + AssemblyRef.MicrosoftVSDesigner),
  24. Editor("Microsoft.VSDesigner.Data.Design.DataSourceEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
  25. DefaultProperty("Table"),
  26. DefaultEvent("PositionChanged")
  27. ]
  28. public class DataView : MarshalByValueComponent, IBindingListView , System.ComponentModel.ITypedList, ISupportInitializeNotification {
  29. private DataViewManager dataViewManager;
  30. private DataTable table;
  31. private bool locked = false;
  32. private Index index;
  33. private Dictionary<string,Index> findIndexes;
  34. private string sort = "";
  35. /// <summary>Allow a user implemented comparision of two DataRow</summary>
  36. /// <remarks>User must use correct DataRowVersion in comparison or index corruption will happen</remarks>
  37. private System.Comparison<DataRow> _comparison;
  38. /// <summary>
  39. /// IFilter will allow LinqDataView to wrap <see cref='System.Predicate&lt;DataRow&gt;'/> instead of using a DataExpression
  40. /// </summary>
  41. private IFilter rowFilter = null;
  42. private DataViewRowState recordStates = DataViewRowState.CurrentRows;
  43. private bool shouldOpen = true;
  44. private bool open = false;
  45. private bool allowNew = true;
  46. private bool allowEdit = true;
  47. private bool allowDelete = true;
  48. private bool applyDefaultSort = false;
  49. internal DataRow addNewRow;
  50. private ListChangedEventArgs addNewMoved;
  51. private System.ComponentModel.ListChangedEventHandler onListChanged;
  52. private System.EventHandler onInitialized;
  53. internal static ListChangedEventArgs ResetEventArgs = new ListChangedEventArgs(ListChangedType.Reset, -1);
  54. private DataTable delayedTable = null;
  55. private string delayedRowFilter = null;
  56. private string delayedSort = null;
  57. private DataViewRowState delayedRecordStates = (DataViewRowState)(-1);
  58. private bool fInitInProgress = false;
  59. private bool fEndInitInProgress = false;
  60. /// <summary>
  61. /// You can't delay create the DataRowView instances since multiple thread read access is valid
  62. /// and each thread must obtain the same DataRowView instance and we want to avoid (inter)locking.
  63. /// </summary>
  64. /// <remarks>
  65. /// In V1.1, the DataRowView[] was recreated after every change. Each DataRowView was bound to a DataRow.
  66. /// In V2.0 Whidbey, the DataRowView retained but bound to an index instead of DataRow, allowing the DataRow to vary.
  67. /// In V2.0 Orcas, the DataRowView retained and bound to a DataRow, allowing the index to vary.
  68. /// </remarks>
  69. private Dictionary<DataRow, DataRowView> rowViewCache = new Dictionary<DataRow, DataRowView>(DataRowReferenceComparer.Default);
  70. /// <summary>
  71. /// This collection allows expression maintaince to (add / remove) from the index when it really should be a (change / move).
  72. /// </summary>
  73. private readonly Dictionary<DataRow, DataRowView> rowViewBuffer = new Dictionary<DataRow, DataRowView>(DataRowReferenceComparer.Default);
  74. private sealed class DataRowReferenceComparer : IEqualityComparer<DataRow> {
  75. internal static readonly DataRowReferenceComparer Default = new DataRowReferenceComparer();
  76. private DataRowReferenceComparer() { }
  77. public bool Equals(DataRow x, DataRow y) {
  78. return ((object)x == (object)y);
  79. }
  80. public int GetHashCode(DataRow obj) {
  81. return obj.ObjectID;
  82. }
  83. }
  84. DataViewListener dvListener = null;
  85. private static int _objectTypeCount; // Bid counter
  86. private readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
  87. internal DataView(DataTable table, bool locked) {
  88. GC.SuppressFinalize(this);
  89. Bid.Trace("<ds.DataView.DataView|INFO> %d#, table=%d, locked=%d{bool}\n", ObjectID, (table != null) ? table.ObjectID : 0, locked);
  90. this.dvListener = new DataViewListener(this);
  91. this.locked = locked;
  92. this.table = table;
  93. dvListener.RegisterMetaDataEvents(this.table);
  94. }
  95. /// <devdoc>
  96. /// <para>Initializes a new instance of the <see cref='System.Data.DataView'/> class.</para>
  97. /// </devdoc>
  98. public DataView() : this(null) {
  99. SetIndex2("", DataViewRowState.CurrentRows, null, true);
  100. }
  101. /// <devdoc>
  102. /// <para>Initializes a new instance of the <see cref='System.Data.DataView'/> class with the
  103. /// specified <see cref='System.Data.DataTable'/>.</para>
  104. /// </devdoc>
  105. public DataView(DataTable table) : this(table, false) {
  106. SetIndex2("", DataViewRowState.CurrentRows, null, true);
  107. }
  108. /// <devdoc>
  109. /// <para>Initializes a new instance of the <see cref='System.Data.DataView'/> class with the
  110. /// specified <see cref='System.Data.DataTable'/>.</para>
  111. /// </devdoc>
  112. public DataView(DataTable table, String RowFilter, string Sort, DataViewRowState RowState) {
  113. GC.SuppressFinalize(this);
  114. Bid.Trace("<ds.DataView.DataView|API> %d#, table=%d, RowFilter='%ls', Sort='%ls', RowState=%d{ds.DataViewRowState}\n",
  115. ObjectID, (table != null) ? table.ObjectID : 0, RowFilter, Sort, (int)RowState);
  116. if (table == null)
  117. throw ExceptionBuilder.CanNotUse();
  118. this.dvListener = new DataViewListener(this);
  119. this.locked = false;
  120. this.table = table;
  121. dvListener.RegisterMetaDataEvents(this.table);
  122. if ((((int)RowState) &
  123. ((int)~(DataViewRowState.CurrentRows | DataViewRowState.OriginalRows))) != 0) {
  124. throw ExceptionBuilder.RecordStateRange();
  125. }
  126. else if (( ((int)RowState) & ((int)DataViewRowState.ModifiedOriginal) ) != 0 &&
  127. ( ((int)RowState) & ((int)DataViewRowState.ModifiedCurrent) ) != 0
  128. ) {
  129. throw ExceptionBuilder.SetRowStateFilter();
  130. }
  131. if (Sort == null)
  132. Sort = "";
  133. if (RowFilter == null)
  134. RowFilter = "";
  135. DataExpression newFilter = new DataExpression(table, RowFilter);
  136. SetIndex(Sort, RowState, newFilter);
  137. }
  138. /// <summary>
  139. /// Allow construction of DataView with <see cref="System.Predicate&lt;DataRow&gt;"/> and <see cref="System.Comparison&lt;DataRow&gt;"/>
  140. /// </summary>
  141. /// <remarks>This is a copy of the other DataView ctor and needs to be kept in [....]</remarks>
  142. internal DataView(DataTable table, System.Predicate<DataRow> predicate, System.Comparison<DataRow> comparison, DataViewRowState RowState) {
  143. GC.SuppressFinalize(this);
  144. Bid.Trace("<ds.DataView.DataView|API> %d#, table=%d, RowState=%d{ds.DataViewRowState}\n",
  145. ObjectID, (table != null) ? table.ObjectID : 0, (int)RowState);
  146. if (table == null)
  147. throw ExceptionBuilder.CanNotUse();
  148. this.dvListener = new DataViewListener(this);
  149. this.locked = false;
  150. this.table = table;
  151. dvListener.RegisterMetaDataEvents(this.table);
  152. if ((((int)RowState) &
  153. ((int)~(DataViewRowState.CurrentRows | DataViewRowState.OriginalRows))) != 0) {
  154. throw ExceptionBuilder.RecordStateRange();
  155. }
  156. else if (( ((int)RowState) & ((int)DataViewRowState.ModifiedOriginal) ) != 0 &&
  157. ( ((int)RowState) & ((int)DataViewRowState.ModifiedCurrent) ) != 0
  158. ) {
  159. throw ExceptionBuilder.SetRowStateFilter();
  160. }
  161. _comparison = comparison;
  162. SetIndex2("", RowState, ((null != predicate) ? new RowPredicateFilter(predicate) : null), true);
  163. }
  164. /// <devdoc>
  165. /// <para>
  166. /// Sets or gets a value indicating whether deletes are
  167. /// allowed.
  168. /// </para>
  169. /// </devdoc>
  170. [
  171. ResCategoryAttribute(Res.DataCategory_Data),
  172. DefaultValue(true),
  173. ResDescriptionAttribute(Res.DataViewAllowDeleteDescr)
  174. ]
  175. public bool AllowDelete {
  176. get {
  177. return allowDelete;
  178. }
  179. set {
  180. if (allowDelete != value) {
  181. allowDelete = value;
  182. OnListChanged(ResetEventArgs);
  183. }
  184. }
  185. }
  186. /// <devdoc>
  187. /// <para>Gets or sets a value indicating whether to use the default sort.</para>
  188. /// </devdoc>
  189. [
  190. RefreshProperties(RefreshProperties.All),
  191. ResCategoryAttribute(Res.DataCategory_Data),
  192. DefaultValue(false),
  193. ResDescriptionAttribute(Res.DataViewApplyDefaultSortDescr)
  194. ]
  195. public bool ApplyDefaultSort {
  196. get {
  197. return applyDefaultSort;
  198. }
  199. set {
  200. Bid.Trace("<ds.DataView.set_ApplyDefaultSort|API> %d#, %d{bool}\n", ObjectID, value);
  201. if (applyDefaultSort != value) {
  202. _comparison = null; // clear the delegate to allow the Sort string to be effective
  203. applyDefaultSort = value;
  204. UpdateIndex(true);
  205. OnListChanged(ResetEventArgs);
  206. }
  207. }
  208. }
  209. /// <devdoc>
  210. /// <para>
  211. /// Gets or sets a value indicating whether edits are allowed.
  212. /// </para>
  213. /// </devdoc>
  214. [
  215. ResCategoryAttribute(Res.DataCategory_Data),
  216. DefaultValue(true),
  217. ResDescriptionAttribute(Res.DataViewAllowEditDescr)
  218. ]
  219. public bool AllowEdit {
  220. get {
  221. return allowEdit;
  222. }
  223. set {
  224. if (allowEdit != value) {
  225. allowEdit = value;
  226. OnListChanged(ResetEventArgs);
  227. }
  228. }
  229. }
  230. /// <devdoc>
  231. /// <para>
  232. /// Gets or sets a value indicating whether the new rows can
  233. /// be added using the <see cref='System.Data.DataView.AddNew'/>
  234. /// method.
  235. /// </para>
  236. /// </devdoc>
  237. [
  238. ResCategoryAttribute(Res.DataCategory_Data),
  239. DefaultValue(true),
  240. ResDescriptionAttribute(Res.DataViewAllowNewDescr)
  241. ]
  242. public bool AllowNew {
  243. get {
  244. return allowNew;
  245. }
  246. set {
  247. if (allowNew != value) {
  248. allowNew = value;
  249. OnListChanged(ResetEventArgs);
  250. }
  251. }
  252. }
  253. /// <summary>
  254. /// Gets the number of records in the <see cref='System.Data.DataView'/>.
  255. /// </summary>
  256. [Browsable(false), ResDescriptionAttribute(Res.DataViewCountDescr)]
  257. public int Count {
  258. get {
  259. Debug.Assert(rowViewCache.Count == CountFromIndex, "DataView.Count mismatch");
  260. return rowViewCache.Count;
  261. }
  262. }
  263. private int CountFromIndex {
  264. get {
  265. return (((null != index) ? index.RecordCount : 0) + ((null != addNewRow) ? 1 : 0));
  266. }
  267. }
  268. /// <devdoc>
  269. /// <para>
  270. /// Gets the <see cref='System.Data.DataViewManager'/> associated with this <see cref='System.Data.DataView'/> .
  271. /// </para>
  272. /// </devdoc>
  273. [Browsable(false), ResDescriptionAttribute(Res.DataViewDataViewManagerDescr)]
  274. public DataViewManager DataViewManager {
  275. get {
  276. return dataViewManager;
  277. }
  278. }
  279. [Browsable(false)]
  280. public bool IsInitialized {
  281. get {
  282. return !fInitInProgress;
  283. }
  284. }
  285. /// <devdoc>
  286. /// <para>
  287. /// Gets a value indicating whether the data source is currently open and
  288. /// projecting views of data on the <see cref='System.Data.DataTable'/>.
  289. /// </para>
  290. /// </devdoc>
  291. [Browsable(false), ResDescriptionAttribute(Res.DataViewIsOpenDescr)]
  292. protected bool IsOpen {
  293. get {
  294. return open;
  295. }
  296. }
  297. bool ICollection.IsSynchronized {
  298. get {
  299. return false;
  300. }
  301. }
  302. /// <devdoc>
  303. /// <para>
  304. /// Gets or sets the expression used to filter which rows are viewed in the
  305. /// <see cref='System.Data.DataView'/>.
  306. /// </para>
  307. /// </devdoc>
  308. [
  309. ResCategoryAttribute(Res.DataCategory_Data),
  310. DefaultValue(""),
  311. ResDescriptionAttribute(Res.DataViewRowFilterDescr)
  312. ]
  313. public virtual string RowFilter {
  314. get { // ACCESSOR: virtual was missing from this get
  315. DataExpression expression = (rowFilter as DataExpression);
  316. return(expression == null ? "" : expression.Expression); //
  317. }
  318. set {
  319. if (value == null)
  320. value = "";
  321. Bid.Trace("<ds.DataView.set_RowFilter|API> %d#, '%ls'\n", ObjectID, value);
  322. if (fInitInProgress) {
  323. delayedRowFilter = value;
  324. return;
  325. }
  326. CultureInfo locale = (table != null ? table.Locale : CultureInfo.CurrentCulture);
  327. if (null == rowFilter || (String.Compare(RowFilter,value,false,locale) != 0)) {
  328. DataExpression newFilter = new DataExpression(table, value);
  329. SetIndex(sort, recordStates, newFilter);
  330. }
  331. }
  332. }
  333. #region RowPredicateFilter
  334. /// <summary>
  335. /// The predicate delegate that will determine if a DataRow should be contained within the view.
  336. /// This RowPredicate property is mutually exclusive with the RowFilter property.
  337. /// </summary>
  338. internal System.Predicate<DataRow> RowPredicate {
  339. get {
  340. RowPredicateFilter filter = (GetFilter() as RowPredicateFilter);
  341. return ((null != filter) ? filter.PredicateFilter : null);
  342. }
  343. set {
  344. if (!Object.ReferenceEquals(RowPredicate, value)) {
  345. SetIndex(Sort, RowStateFilter, ((null != value) ? new RowPredicateFilter(value) : null));
  346. }
  347. }
  348. }
  349. /// <summary></summary>
  350. private sealed class RowPredicateFilter : System.Data.IFilter {
  351. internal readonly System.Predicate<DataRow> PredicateFilter;
  352. /// <summary></summary>
  353. internal RowPredicateFilter(System.Predicate<DataRow> predicate) {
  354. Debug.Assert(null != predicate, "null predicate");
  355. PredicateFilter = predicate;
  356. }
  357. /// <summary></summary>
  358. bool IFilter.Invoke(DataRow row, DataRowVersion version) {
  359. Debug.Assert(DataRowVersion.Default != version, "not expecting Default");
  360. Debug.Assert(DataRowVersion.Proposed != version, "not expecting Proposed");
  361. return PredicateFilter(row);
  362. }
  363. }
  364. #endregion
  365. /// <devdoc>
  366. /// <para>Gets or sets the row state filter used in the <see cref='System.Data.DataView'/>.</para>
  367. /// </devdoc>
  368. [
  369. ResCategoryAttribute(Res.DataCategory_Data),
  370. DefaultValue(DataViewRowState.CurrentRows),
  371. ResDescriptionAttribute(Res.DataViewRowStateFilterDescr)
  372. ]
  373. public DataViewRowState RowStateFilter {
  374. get {
  375. return recordStates;
  376. }
  377. set {
  378. Bid.Trace("<ds.DataView.set_RowStateFilter|API> %d#, %d{ds.DataViewRowState}\n", ObjectID, (int)value);
  379. if (fInitInProgress) {
  380. delayedRecordStates = value;
  381. return;
  382. }
  383. if ((((int)value) &
  384. ((int)~(DataViewRowState.CurrentRows | DataViewRowState.OriginalRows))) != 0)
  385. throw ExceptionBuilder.RecordStateRange();
  386. else if (( ((int)value) & ((int)DataViewRowState.ModifiedOriginal) ) != 0 &&
  387. ( ((int)value) & ((int)DataViewRowState.ModifiedCurrent) ) != 0
  388. )
  389. throw ExceptionBuilder.SetRowStateFilter();
  390. if (recordStates != value) {
  391. SetIndex(sort, value, rowFilter);
  392. }
  393. }
  394. }
  395. /// <devdoc>
  396. /// <para>
  397. /// Gets
  398. /// or sets the sort column or columns, and sort order for the table.
  399. /// </para>
  400. /// </devdoc>
  401. [
  402. ResCategoryAttribute(Res.DataCategory_Data),
  403. DefaultValue(""),
  404. ResDescriptionAttribute(Res.DataViewSortDescr)
  405. ]
  406. public string Sort {
  407. get {
  408. if (sort.Length == 0 && applyDefaultSort && table != null && table._primaryIndex.Length > 0) {
  409. return table.FormatSortString(table._primaryIndex);
  410. }
  411. else {
  412. return sort;
  413. }
  414. }
  415. set {
  416. if (value == null) {
  417. value = "";
  418. }
  419. Bid.Trace("<ds.DataView.set_Sort|API> %d#, '%ls'\n", ObjectID, value);
  420. if (fInitInProgress) {
  421. delayedSort = value;
  422. return;
  423. }
  424. CultureInfo locale = (table != null ? table.Locale : CultureInfo.CurrentCulture);
  425. if (String.Compare(sort, value, false, locale) != 0 || (null != _comparison)) {
  426. CheckSort(value);
  427. _comparison = null; // clear the delegate to allow the Sort string to be effective
  428. SetIndex(value, recordStates, rowFilter);
  429. }
  430. }
  431. }
  432. /// <summary>Allow a user implemented comparision of two DataRow</summary>
  433. /// <remarks>User must use correct DataRowVersion in comparison or index corruption will happen</remarks>
  434. internal System.Comparison<DataRow> SortComparison {
  435. get {
  436. return _comparison;
  437. }
  438. set {
  439. Bid.Trace("<ds.DataView.set_SortComparison|API> %d#\n", ObjectID);
  440. if (!Object.ReferenceEquals(_comparison, value)) {
  441. _comparison = value;
  442. SetIndex("", recordStates, rowFilter);
  443. }
  444. }
  445. }
  446. /// <devdoc>
  447. /// <para>
  448. /// Resets the <see cref='System.Data.DataView.Sort'/> property to its default state.
  449. /// </para>
  450. /// </devdoc>
  451. private void ResetSort() {
  452. // this is dead code, no one is calling it
  453. sort = "";
  454. SetIndex(sort, recordStates, rowFilter);
  455. }
  456. /// <devdoc>
  457. /// <para>
  458. /// Indicates whether the <see cref='System.Data.DataView.Sort'/> property should be persisted.
  459. /// </para>
  460. /// </devdoc>
  461. private bool ShouldSerializeSort() {
  462. return(sort != null);
  463. }
  464. object ICollection.SyncRoot {
  465. get {
  466. return this;
  467. }
  468. }
  469. /// <devdoc>
  470. /// <para>
  471. /// Gets or sets the source <see cref='System.Data.DataTable'/>.
  472. /// </para>
  473. /// </devdoc>
  474. [
  475. TypeConverterAttribute(typeof(DataTableTypeConverter)),
  476. ResCategoryAttribute(Res.DataCategory_Data),
  477. DefaultValue(null),
  478. RefreshProperties(RefreshProperties.All),
  479. ResDescriptionAttribute(Res.DataViewTableDescr)
  480. ]
  481. public DataTable Table {
  482. get {
  483. return table;
  484. }
  485. set {
  486. Bid.Trace("<ds.DataView.set_Table|API> %d#, %d\n", ObjectID, (value != null) ? value.ObjectID : 0);
  487. if (fInitInProgress && value != null) {
  488. delayedTable = value;
  489. return;
  490. }
  491. if (locked)
  492. throw ExceptionBuilder.SetTable();
  493. if (dataViewManager != null)
  494. throw ExceptionBuilder.CanNotSetTable();
  495. if (value != null && value.TableName.Length == 0)
  496. throw ExceptionBuilder.CanNotBindTable();
  497. if (table != value) {
  498. dvListener.UnregisterMetaDataEvents();
  499. table = value;
  500. if (table != null) {
  501. dvListener.RegisterMetaDataEvents(this.table);
  502. }
  503. // SQLBU 427284: ListChanged event was being fired after the table change, before the index update.
  504. SetIndex2("", DataViewRowState.CurrentRows, null, false);
  505. if (table != null) {
  506. OnListChanged(new ListChangedEventArgs(ListChangedType.PropertyDescriptorChanged, new DataTablePropertyDescriptor(table)));
  507. }
  508. // index was updated without firing the reset, fire it now
  509. OnListChanged(ResetEventArgs);
  510. }
  511. }
  512. }
  513. object IList.this[int recordIndex] {
  514. get {
  515. return this[recordIndex];
  516. }
  517. set {
  518. throw ExceptionBuilder.SetIListObject();
  519. }
  520. }
  521. /// <devdoc>
  522. /// <para>
  523. /// Gets a row of data from a specified table.
  524. /// </para>
  525. /// </devdoc>
  526. /// <exception cref="IndexOutOfRangeException"></exception>
  527. public DataRowView this[int recordIndex] {
  528. get {
  529. return GetRowView(GetRow(recordIndex));
  530. }
  531. }
  532. /// <summary>
  533. /// Adds a new row of data to view.
  534. /// </summary>
  535. /// <remarks>
  536. /// Only one new row of data allowed at a time, so previous new row will be added to row collection.
  537. /// Unsupported pattern: dataTable.Rows.Add(dataView.AddNew().Row)
  538. /// </remarks>
  539. public virtual DataRowView AddNew() {
  540. IntPtr hscp;
  541. Bid.ScopeEnter(out hscp, "<ds.DataView.AddNew|API> %d#\n", ObjectID);
  542. try {
  543. CheckOpen();
  544. if (!AllowNew)
  545. throw ExceptionBuilder.AddNewNotAllowNull();
  546. if (addNewRow != null) {
  547. rowViewCache[addNewRow].EndEdit();
  548. }
  549. Debug.Assert(null == addNewRow, "AddNew addNewRow is not null");
  550. addNewRow = table.NewRow();
  551. DataRowView drv = new DataRowView(this, addNewRow);
  552. rowViewCache.Add(addNewRow, drv);
  553. OnListChanged(new ListChangedEventArgs(ListChangedType.ItemAdded, IndexOf(drv)));
  554. return drv;
  555. }
  556. finally{
  557. Bid.ScopeLeave(ref hscp);
  558. }
  559. }
  560. public void BeginInit() {
  561. fInitInProgress = true;
  562. }
  563. public void EndInit() {
  564. if (delayedTable != null && this.delayedTable.fInitInProgress) {
  565. this.delayedTable.delayedViews.Add(this);
  566. return;
  567. }
  568. fInitInProgress = false;
  569. fEndInitInProgress = true;
  570. if (delayedTable != null) {
  571. Table = delayedTable;
  572. delayedTable = null;
  573. }
  574. if (delayedSort != null) {
  575. Sort = delayedSort;
  576. delayedSort = null;
  577. }
  578. if (delayedRowFilter != null) {
  579. RowFilter = delayedRowFilter;
  580. delayedRowFilter = null;
  581. }
  582. if (delayedRecordStates != (DataViewRowState)(-1)) {
  583. RowStateFilter = delayedRecordStates;
  584. delayedRecordStates = (DataViewRowState)(-1);
  585. }
  586. fEndInitInProgress = false;
  587. SetIndex(Sort, RowStateFilter, rowFilter);
  588. OnInitialized();
  589. }
  590. private void CheckOpen() {
  591. if (!IsOpen) throw ExceptionBuilder.NotOpen();
  592. }
  593. private void CheckSort(string sort) {
  594. if (table == null)
  595. throw ExceptionBuilder.CanNotUse();
  596. if (sort.Length == 0)
  597. return;
  598. table.ParseSortString(sort);
  599. }
  600. /// <devdoc>
  601. /// <para>
  602. /// Closes the <see cref='System.Data.DataView'/>
  603. /// .
  604. /// </para>
  605. /// </devdoc>
  606. protected void Close() {
  607. shouldOpen = false;
  608. UpdateIndex();
  609. dvListener.UnregisterMetaDataEvents();
  610. }
  611. public void CopyTo(Array array, int index) {
  612. if (null != this.index) {
  613. RBTree<int>.RBTreeEnumerator iterator = this.index.GetEnumerator(0);
  614. while (iterator.MoveNext()) {
  615. array.SetValue(GetRowView(iterator.Current), index);
  616. checked {
  617. index++;
  618. }
  619. }
  620. }
  621. if (null != addNewRow) {
  622. array.SetValue(rowViewCache[addNewRow], index);
  623. }
  624. }
  625. private void CopyTo(DataRowView[] array, int index) {
  626. if (null != this.index) {
  627. RBTree<int>.RBTreeEnumerator iterator = this.index.GetEnumerator(0);
  628. while (iterator.MoveNext()) {
  629. array[index] = GetRowView(iterator.Current);
  630. checked {
  631. index++;
  632. }
  633. }
  634. }
  635. if (null != addNewRow) {
  636. array[index] = rowViewCache[addNewRow];
  637. }
  638. }
  639. /// <devdoc>
  640. /// <para>Deletes a row at the specified index.</para>
  641. /// </devdoc>
  642. public void Delete(int index) {
  643. Delete(GetRow(index));
  644. }
  645. internal void Delete(DataRow row) {
  646. if (null != row) {
  647. IntPtr hscp;
  648. Bid.ScopeEnter(out hscp, "<ds.DataView.Delete|API> %d#, row=%d#", ObjectID, row.ObjectID);
  649. try {
  650. CheckOpen();
  651. if (row == addNewRow) {
  652. FinishAddNew(false);
  653. return;
  654. }
  655. if (!AllowDelete)
  656. {
  657. throw ExceptionBuilder.CanNotDelete();
  658. }
  659. row.Delete();
  660. }
  661. finally {
  662. Bid.ScopeLeave(ref hscp);
  663. }
  664. }
  665. }
  666. protected override void Dispose(bool disposing) {
  667. if (disposing) {
  668. Close();
  669. }
  670. base.Dispose(disposing);
  671. }
  672. /// <devdoc>
  673. /// <para>
  674. /// Finds a row in the <see cref='System.Data.DataView'/> by the specified primary key
  675. /// value.
  676. /// </para>
  677. /// </devdoc>
  678. public int Find(object key) {
  679. return FindByKey(key);
  680. }
  681. /// <summary>Find index of a DataRowView instance that matches the specified primary key value.</summary>
  682. internal virtual int FindByKey(object key) {
  683. return index.FindRecordByKey(key);
  684. }
  685. /// <devdoc>
  686. /// <para>
  687. /// Finds a row in the <see cref='System.Data.DataView'/> by the specified primary key values.
  688. /// </para>
  689. /// </devdoc>
  690. public int Find(object[] key) {
  691. return FindByKey(key);
  692. }
  693. /// <summary>Find index of a DataRowView instance that matches the specified primary key values.</summary>
  694. internal virtual int FindByKey(object[] key) {
  695. return index.FindRecordByKey(key);
  696. }
  697. /// <devdoc>
  698. /// <para>
  699. /// Finds a row in the <see cref='System.Data.DataView'/> by the specified primary key
  700. /// value.
  701. /// </para>
  702. /// </devdoc>
  703. public DataRowView[] FindRows(object key) {
  704. return FindRowsByKey(new object[] {key});
  705. }
  706. /// <devdoc>
  707. /// <para>
  708. /// Finds a row in the <see cref='System.Data.DataView'/> by the specified primary key values.
  709. /// </para>
  710. /// </devdoc>
  711. public DataRowView[] FindRows(object[] key) {
  712. return FindRowsByKey(key);
  713. }
  714. /// <summary>Find DataRowView instances that match the specified primary key values.</summary>
  715. internal virtual DataRowView[] FindRowsByKey(object[] key) {
  716. IntPtr hscp;
  717. Bid.ScopeEnter(out hscp, "<ds.DataView.FindRows|API> %d#\n", ObjectID);
  718. try {
  719. Range range = index.FindRecords(key);
  720. return GetDataRowViewFromRange(range);
  721. }
  722. finally{
  723. Bid.ScopeLeave(ref hscp);
  724. }
  725. }
  726. /// <summary>This method exists for LinqDataView to keep a level of abstraction away from the RBTree</summary>
  727. internal Range FindRecords<TKey,TRow>(Index.ComparisonBySelector<TKey,TRow> comparison, TKey key) where TRow:DataRow
  728. {
  729. return this.index.FindRecords(comparison, key);
  730. }
  731. /// <summary>Convert a Range into a DataRowView[].</summary>
  732. internal DataRowView[] GetDataRowViewFromRange(Range range)
  733. {
  734. if (range.IsNull) {
  735. return new DataRowView[0];
  736. }
  737. DataRowView[] rows = new DataRowView[range.Count];
  738. for (int i=0; i<rows.Length; i++) {
  739. rows[i] = this[i + range.Min];
  740. }
  741. return rows;
  742. }
  743. internal void FinishAddNew(bool success) {
  744. Debug.Assert(null != addNewRow, "null addNewRow");
  745. Bid.Trace("<ds.DataView.FinishAddNew|INFO> %d#, success=%d{bool}\n", ObjectID, success);
  746. DataRow newRow = addNewRow;
  747. if (success) {
  748. if (DataRowState.Detached == newRow.RowState) {
  749. // MaintainDataView will translate the ItemAdded from the RowCollection into
  750. // into either an ItemMoved or no event, since it didn't change position.
  751. // also possible it's added to the RowCollection but filtered out of the view.
  752. table.Rows.Add(newRow);
  753. }
  754. else {
  755. // this means that the record was added to the table by different means and not part of view
  756. newRow.EndEdit();
  757. }
  758. }
  759. if (newRow == addNewRow) {
  760. // this means that the record did not get to the view
  761. bool flag = rowViewCache.Remove(addNewRow);
  762. Debug.Assert(flag, "didn't remove addNewRow");
  763. addNewRow = null;
  764. if (!success) {
  765. newRow.CancelEdit();
  766. }
  767. OnListChanged(new ListChangedEventArgs(ListChangedType.ItemDeleted, Count));
  768. }
  769. }
  770. /// <devdoc>
  771. /// <para>
  772. /// Gets an enumerator for this <see cref='System.Data.DataView'/>.
  773. /// </para>
  774. /// </devdoc>
  775. public IEnumerator GetEnumerator() {
  776. // V1.1 compatability: returning List<DataRowView>.GetEnumerator() from RowViewCache
  777. // prevents users from changing data without invalidating the enumerator
  778. // aka don't 'return this.RowViewCache.GetEnumerator()'
  779. DataRowView[] temp = new DataRowView[this.Count];
  780. this.CopyTo(temp, 0);
  781. return temp.GetEnumerator();
  782. }
  783. #region IList
  784. bool IList.IsReadOnly {
  785. get {
  786. return false;
  787. }
  788. }
  789. bool IList.IsFixedSize {
  790. get {
  791. return false;
  792. }
  793. }
  794. int IList.Add(object value) {
  795. if (value == null) {
  796. // null is default value, so we AddNew.
  797. AddNew();
  798. return Count - 1;
  799. }
  800. throw ExceptionBuilder.AddExternalObject();
  801. }
  802. void IList.Clear() {
  803. throw ExceptionBuilder.CanNotClear();
  804. }
  805. bool IList.Contains(object value) {
  806. return (0 <= IndexOf(value as DataRowView));
  807. }
  808. int IList.IndexOf(object value) {
  809. return IndexOf(value as DataRowView);
  810. }
  811. /// <summary>Return positional index of a <see cref="DataRowView"/> in this DataView</summary>
  812. /// <remarks>Behavioral change: will now return -1 once a DataRowView becomes detached.</remarks>
  813. internal int IndexOf(DataRowView rowview) {
  814. if (null != rowview) {
  815. if (Object.ReferenceEquals(addNewRow, rowview.Row)) {
  816. return Count - 1;
  817. }
  818. if ((null != index) && (DataRowState.Detached != rowview.Row.RowState)) {
  819. DataRowView cached; // verify the DataRowView is one we currently track - not something previously detached
  820. if (rowViewCache.TryGetValue(rowview.Row, out cached) && ((object)cached == (object)rowview)) {
  821. return IndexOfDataRowView(rowview);
  822. }
  823. }
  824. }
  825. return -1;
  826. }
  827. private int IndexOfDataRowView(DataRowView rowview) {
  828. // rowview.GetRecord() may return the proposed record
  829. // the index will only contain the original or current record, never proposed.
  830. // return index.GetIndex(rowview.GetRecord());
  831. return index.GetIndex(rowview.Row.GetRecordFromVersion(rowview.Row.GetDefaultRowVersion(this.RowStateFilter) & ~DataRowVersion.Proposed));
  832. }
  833. void IList.Insert(int index, object value) {
  834. throw ExceptionBuilder.InsertExternalObject();
  835. }
  836. void IList.Remove(object value) {
  837. int index = IndexOf(value as DataRowView);
  838. if (0 <= index) {
  839. // must delegate to IList.RemoveAt
  840. ((IList)this).RemoveAt(index);
  841. }
  842. else {
  843. throw ExceptionBuilder.RemoveExternalObject();
  844. }
  845. }
  846. void IList.RemoveAt(int index) {
  847. Delete(index);
  848. }
  849. internal Index GetFindIndex(string column, bool keepIndex) {
  850. if (findIndexes == null) {
  851. findIndexes = new Dictionary<string,Index>();
  852. }
  853. Index findIndex;
  854. if (findIndexes.TryGetValue(column, out findIndex)) {
  855. if (!keepIndex) {
  856. findIndexes.Remove(column);
  857. findIndex.RemoveRef();
  858. if (findIndex.RefCount == 1) { // if we have created it and we are removing it, refCount is (1)
  859. findIndex.RemoveRef(); // if we are reusing the index created by others, refcount is (2)
  860. }
  861. }
  862. }
  863. else {
  864. if (keepIndex) {
  865. findIndex = table.GetIndex(column, recordStates, GetFilter());
  866. findIndexes[column] = findIndex;
  867. findIndex.AddRef();
  868. }
  869. }
  870. return findIndex;
  871. }
  872. #endregion
  873. #region IBindingList implementation
  874. bool IBindingList.AllowNew {
  875. get { return AllowNew; }
  876. }
  877. object IBindingList.AddNew() {
  878. return AddNew();
  879. }
  880. bool IBindingList.AllowEdit {
  881. get { return AllowEdit; }
  882. }
  883. bool IBindingList.AllowRemove {
  884. get { return AllowDelete; }
  885. }
  886. bool IBindingList.SupportsChangeNotification {
  887. get { return true; }
  888. }
  889. bool IBindingList.SupportsSearching {
  890. get { return true; }
  891. }
  892. bool IBindingList.SupportsSorting {
  893. get { return true; }
  894. }
  895. bool IBindingList.IsSorted {
  896. get { return this.Sort.Length != 0; }
  897. }
  898. PropertyDescriptor IBindingList.SortProperty {
  899. get {
  900. return GetSortProperty();
  901. }
  902. }
  903. internal PropertyDescriptor GetSortProperty() {
  904. if (table != null && index != null && index.IndexFields.Length == 1) {
  905. return new DataColumnPropertyDescriptor(index.IndexFields[0].Column);
  906. }
  907. return null;
  908. }
  909. ListSortDirection IBindingList.SortDirection {
  910. get {
  911. if (index.IndexFields.Length == 1 && index.IndexFields[0].IsDescending) {
  912. return ListSortDirection.Descending;
  913. }
  914. return ListSortDirection.Ascending;
  915. }
  916. }
  917. #endregion
  918. #region ListChanged & Initialized events
  919. /// <devdoc>
  920. /// <para>
  921. /// Occurs when the list managed by the <see cref='System.Data.DataView'/> changes.
  922. /// </para>
  923. /// </devdoc>
  924. [ResCategoryAttribute(Res.DataCategory_Data), ResDescriptionAttribute(Res.DataViewListChangedDescr)]
  925. public event System.ComponentModel.ListChangedEventHandler ListChanged {
  926. add {
  927. Bid.Trace("<ds.DataView.add_ListChanged|API> %d#\n", ObjectID);
  928. onListChanged += value;
  929. }
  930. remove {
  931. Bid.Trace("<ds.DataView.remove_ListChanged|API> %d#\n", ObjectID);
  932. onListChanged -= value;
  933. }
  934. }
  935. [
  936. ResCategoryAttribute(Res.DataCategory_Action),
  937. ResDescriptionAttribute(Res.DataSetInitializedDescr)
  938. ]
  939. public event System.EventHandler Initialized {
  940. add {
  941. onInitialized += value;
  942. }
  943. remove {
  944. onInitialized -= value;
  945. }
  946. }
  947. #endregion
  948. #region IBindingList implementation
  949. void IBindingList.AddIndex(PropertyDescriptor property) {
  950. GetFindIndex(property.Name, /*keepIndex:*/true);
  951. }
  952. void IBindingList.ApplySort(PropertyDescriptor property, ListSortDirection direction) {
  953. this.Sort = CreateSortString(property, direction);
  954. }
  955. int IBindingList.Find(PropertyDescriptor property, object key) { // NOTE: this function had keepIndex previosely
  956. if (property != null) {
  957. bool created = false;
  958. Index findIndex = null;
  959. try {
  960. if ((null == findIndexes) || !findIndexes.TryGetValue(property.Name, out findIndex)) {
  961. created = true;
  962. findIndex = table.GetIndex(property.Name, recordStates, GetFilter());
  963. findIndex.AddRef();
  964. }
  965. Range recordRange = findIndex.FindRecords(key);
  966. if (!recordRange.IsNull) {
  967. // check to see if key is equal
  968. return index.GetIndex(findIndex.GetRecord(recordRange.Min));
  969. }
  970. }
  971. finally {
  972. if (created && (null != findIndex)) {
  973. findIndex.RemoveRef();
  974. if (findIndex.RefCount == 1) { // if we have created it and we are removing it, refCount is (1)
  975. findIndex.RemoveRef(); // if we are reusing the index created by others, refcount is (2)
  976. }
  977. }
  978. }
  979. }
  980. return -1;
  981. }
  982. void IBindingList.RemoveIndex(PropertyDescriptor property) {
  983. // Ups: If we don't have index yet we will create it before destroing; Fix this later
  984. GetFindIndex(property.Name, /*keepIndex:*/false);
  985. }
  986. void IBindingList.RemoveSort() {
  987. Bid.Trace("<ds.DataView.RemoveSort|API> %d#\n", ObjectID);
  988. this.Sort = string.Empty;
  989. }
  990. #endregion
  991. #region Additional method and properties for new interface IBindingListView
  992. void IBindingListView.ApplySort(ListSortDescriptionCollection sorts) {
  993. if (sorts == null)
  994. throw ExceptionBuilder.ArgumentNull("sorts");
  995. StringBuilder sortString = new StringBuilder();
  996. bool addCommaToString = false;
  997. foreach(ListSortDescription sort in sorts) {
  998. if (sort == null)
  999. throw ExceptionBuilder.ArgumentContainsNull("sorts");
  1000. PropertyDescriptor property = sort.PropertyDescriptor;
  1001. if (property == null)
  1002. throw ExceptionBuilder.ArgumentNull("PropertyDescriptor");
  1003. if (!this.table.Columns.Contains(property.Name)) { // just check if column does not exist, we will handle duplicate column in Sort
  1004. throw ExceptionBuilder.ColumnToSortIsOutOfRange(property.Name);
  1005. }
  1006. ListSortDirection direction = sort.SortDirection;
  1007. if (addCommaToString) // (sortStr.Length != 0)
  1008. sortString.Append(',');
  1009. sortString.Append(CreateSortString(property, direction));
  1010. if (!addCommaToString)
  1011. addCommaToString = true;
  1012. }
  1013. this.Sort = sortString.ToString(); // what if we dont have any valid sort criteira? we would reset the sort
  1014. }
  1015. private string CreateSortString(PropertyDescriptor property, ListSortDirection direction) {
  1016. Debug.Assert (property != null, "property is null");
  1017. StringBuilder resultString = new StringBuilder();
  1018. resultString.Append('[');
  1019. resultString.Append(property.Name);
  1020. resultString.Append(']');
  1021. if (ListSortDirection.Descending == direction) {
  1022. resultString.Append(" DESC");
  1023. }
  1024. return resultString.ToString();
  1025. }
  1026. void IBindingListView.RemoveFilter() {
  1027. Bid.Trace("<ds.DataView.RemoveFilter|API> %d#\n", ObjectID);
  1028. this.RowFilter = "";
  1029. }
  1030. string IBindingListView.Filter {
  1031. get { return this.RowFilter; }
  1032. set { this.RowFilter = value; }
  1033. }
  1034. ListSortDescriptionCollection IBindingListView.SortDescriptions {
  1035. get {
  1036. return GetSortDescriptions();
  1037. }
  1038. }
  1039. internal ListSortDescriptionCollection GetSortDescriptions() {
  1040. ListSortDescription[] sortDescArray = new ListSortDescription[0];
  1041. if (table != null && index != null && index.IndexFields.Length > 0) {
  1042. sortDescArray = new ListSortDescription[index.IndexFields.Length];
  1043. for(int i = 0; i < index.IndexFields.Length; i++ ) {
  1044. DataColumnPropertyDescriptor columnProperty = new DataColumnPropertyDescriptor(index.IndexFields[i].Column);
  1045. if (index.IndexFields[i].IsDescending) {
  1046. sortDescArray[i] = new ListSortDescription(columnProperty, ListSortDirection.Descending);
  1047. }
  1048. else {
  1049. sortDescArray[i] = new ListSortDescription(columnProperty, ListSortDirection.Ascending);
  1050. }
  1051. }
  1052. }
  1053. return new ListSortDescriptionCollection(sortDescArray);
  1054. }
  1055. bool IBindingListView.SupportsAdvancedSorting {
  1056. get { return true; }
  1057. }
  1058. bool IBindingListView.SupportsFiltering {
  1059. get { return true; }
  1060. }
  1061. #endregion
  1062. #region ITypedList
  1063. string System.ComponentModel.ITypedList.GetListName(PropertyDescriptor[] listAccessors) {
  1064. if(table != null) {
  1065. if (listAccessors == null || listAccessors.Length == 0) {
  1066. return table.TableName;
  1067. }
  1068. else {
  1069. DataSet dataSet = table.DataSet;
  1070. if (dataSet != null) {
  1071. DataTable foundTable = dataSet.FindTable(table, listAccessors, 0);
  1072. if (foundTable != null) {
  1073. return foundTable.TableName;
  1074. }
  1075. }
  1076. }
  1077. }
  1078. return String.Empty;
  1079. }
  1080. PropertyDescriptorCollection System.ComponentModel.ITypedList.GetItemProperties(PropertyDescriptor[] listAccessors) {
  1081. if (table != null) {
  1082. if (listAccessors == null || listAccessors.Length == 0) {
  1083. return table.GetPropertyDescriptorCollection(null);
  1084. }
  1085. else {
  1086. DataSet dataSet = table.DataSet;
  1087. if (dataSet == null)
  1088. return new PropertyDescriptorCollection(null);
  1089. DataTable foundTable = dataSet.FindTable(table, listAccessors, 0);
  1090. if (foundTable != null) {
  1091. return foundTable.GetPropertyDescriptorCollection(null);
  1092. }
  1093. }
  1094. }
  1095. return new PropertyDescriptorCollection(null);
  1096. }
  1097. #endregion
  1098. /// <devdoc>
  1099. /// <para>
  1100. /// Gets the filter for the <see cref='System.Data.DataView'/>.
  1101. /// </para>
  1102. /// </devdoc>
  1103. internal virtual IFilter GetFilter() {
  1104. return rowFilter;
  1105. }
  1106. private int GetRecord(int recordIndex) {
  1107. if (unchecked((uint)Count <= (uint)recordIndex))
  1108. throw ExceptionBuilder.RowOutOfRange(recordIndex);
  1109. if (recordIndex == index.RecordCount)
  1110. return addNewRow.GetDefaultRecord();
  1111. return index.GetRecord(recordIndex);
  1112. }
  1113. /// <exception cref="IndexOutOfRangeException"></exception>
  1114. internal DataRow GetRow(int index) {
  1115. int count = Count;
  1116. if (unchecked((uint)count <= (uint)index)) {
  1117. throw ExceptionBuilder.GetElementIndex(index);
  1118. }
  1119. if ((index == (count - 1)) && (addNewRow != null)) {
  1120. // if we could rely on tempRecord being registered with recordManager
  1121. // then this special case code would go away
  1122. return addNewRow;
  1123. }
  1124. return table.recordManager[GetRecord(index)];
  1125. }
  1126. private DataRowView GetRowView(int record) {
  1127. return GetRowView(table.recordManager[record]);
  1128. }
  1129. private DataRowView GetRowView(DataRow dr) {
  1130. return rowViewCache[dr];
  1131. }
  1132. protected virtual void IndexListChanged(object sender, ListChangedEventArgs e) {
  1133. if (ListChangedType.Reset != e.ListChangedType) {
  1134. OnListChanged(e);
  1135. }
  1136. if (addNewRow != null && index.RecordCount == 0) { // [....] : 83032 Clear the newly added row as the underlying index is reset.
  1137. FinishAddNew(false);
  1138. }
  1139. if (ListChangedType.Reset == e.ListChangedType) {
  1140. OnListChanged(e);
  1141. }
  1142. }
  1143. internal void IndexListChangedInternal(ListChangedEventArgs e) {
  1144. rowViewBuffer.Clear();
  1145. if ((ListChangedType.ItemAdded == e.ListChangedType) && (null != addNewMoved)) {
  1146. if (addNewMoved.NewIndex == addNewMoved.OldIndex) {
  1147. // ItemAdded for addNewRow which didn't change position
  1148. // RowStateChange only triggers RowChanged, not ListChanged
  1149. }
  1150. else {
  1151. // translate the ItemAdded into ItemMoved for addNewRow adding into sorted collection
  1152. ListChangedEventArgs f = addNewMoved;
  1153. addNewMoved = null;
  1154. IndexListChanged(this, f);
  1155. }
  1156. }
  1157. // the ItemAdded has to fire twice for AddNewRow (public IBindingList API documentation)
  1158. IndexListChanged(this, e);
  1159. }
  1160. internal void MaintainDataView(ListChangedType changedType, DataRow row, bool trackAddRemove) {
  1161. DataRowView buffer = null;
  1162. switch (changedType) {
  1163. case ListChangedType.ItemAdded:
  1164. Debug.Assert(null != row, "MaintainDataView.ItemAdded with null DataRow");
  1165. if (trackAddRemove) {
  1166. if (rowViewBuffer.TryGetValue(row, out buffer)) {
  1167. // help turn expression add/remove into a changed/move
  1168. bool flag = rowViewBuffer.Remove(row);
  1169. Debug.Assert(flag, "row actually removed");
  1170. }
  1171. }
  1172. if (row == addNewRow) {
  1173. // DataView.AddNew().Row was added to DataRowCollection
  1174. int index = IndexOfDataRowView(rowViewCache[addNewRow]);
  1175. Debug.Assert(0 <= index, "ItemAdded was actually deleted");
  1176. addNewRow = null;
  1177. addNewMoved = new ListChangedEventArgs(ListChangedType.ItemMoved, index, Count - 1);
  1178. }
  1179. else if (!rowViewCache.ContainsKey(row)) {
  1180. rowViewCache.Add(row, buffer ?? new DataRowView(this, row));
  1181. }
  1182. else {
  1183. Debug.Assert(false, "ItemAdded DataRow already in view");
  1184. }
  1185. break;
  1186. case ListChangedType.ItemDeleted:
  1187. Debug.Assert(null != row, "MaintainDataView.ItemDeleted with null DataRow");
  1188. Debug.Assert(row != addNewRow, "addNewRow being deleted");
  1189. if (trackAddRemove) {
  1190. // help turn expression add/remove into a changed/move
  1191. rowViewCache.TryGetValue(row, out buffer);
  1192. if (null != buffer) {
  1193. rowViewBuffer.Add(row, buffer);
  1194. }
  1195. else {
  1196. Debug.Assert(false, "ItemDeleted DataRow not in view tracking");
  1197. }
  1198. }
  1199. if (!rowViewCache.Remove(row)) {
  1200. Debug.Assert(false, "ItemDeleted DataRow not in view");
  1201. }
  1202. break;
  1203. case ListChangedType.Reset:
  1204. Debug.Assert(null == row, "MaintainDataView.Reset with non-null DataRow");
  1205. ResetRowViewCache();
  1206. break;
  1207. case ListChangedType.ItemChanged:
  1208. case ListChangedType.ItemMoved:
  1209. break;
  1210. case ListChangedType.PropertyDescriptorAdded:
  1211. case ListChangedType.PropertyDescriptorChanged:
  1212. case ListChangedType.PropertyDescriptorDeleted:
  1213. Debug.Assert(false, "unexpected");
  1214. break;
  1215. }
  1216. }
  1217. /// <devdoc>
  1218. /// <para>
  1219. /// Raises the <see cref='E:System.Data.DataView.ListChanged'/> event.
  1220. /// </para>
  1221. /// </devdoc>
  1222. protected virtual void OnListChanged(ListChangedEventArgs e) {
  1223. Bid.Trace("<ds.DataView.OnListChanged|INFO> %d#, ListChangedType=%d{ListChangedType}\n", ObjectID, (int)e.ListChangedType);
  1224. try {
  1225. DataColumn col = null;
  1226. string propertyName = null;
  1227. switch (e.ListChangedType) {
  1228. case ListChangedType.ItemChanged:
  1229. // ItemChanged - a column value changed (0 <= e.OldIndex)
  1230. // ItemChanged - a DataRow.RowError changed (-1 == e.OldIndex)
  1231. // ItemChanged - RowState changed (e.NewIndex == e.OldIndex)
  1232. case ListChangedType.ItemMoved:
  1233. // ItemMoved - a column value affecting sort order changed
  1234. // ItemMoved - a state change in equivalent fields
  1235. Debug.Assert(((ListChangedType.ItemChanged == e.ListChangedType) && ((e.NewIndex == e.OldIndex) || (-1 == e.OldIndex))) ||
  1236. (ListChangedType.ItemMoved == e.ListChangedType && (e.NewIndex != e.OldIndex) && (0 <= e.OldIndex)),
  1237. "unexpected ItemChanged|ItemMoved");
  1238. Debug.Assert(0 <= e.NewIndex, "negative NewIndex");
  1239. if (0 <= e.NewIndex) {
  1240. DataRow dr = GetRow(e.NewIndex);
  1241. if (dr.HasPropertyChanged) {
  1242. col = dr.LastChangedColumn;
  1243. propertyName = (null != col) ? col.ColumnName : String.Empty;
  1244. }
  1245. }
  1246. break;
  1247. case ListChangedType.ItemAdded:
  1248. case ListChangedType.ItemDeleted:
  1249. case ListChangedType.PropertyDescriptorAdded:
  1250. case ListChangedType.PropertyDescriptorChanged:
  1251. case ListChangedType.PropertyDescriptorDeleted:
  1252. case ListChangedType.Reset:
  1253. break;
  1254. }
  1255. if (onListChanged != null) {
  1256. if ((col != null) && (e.NewIndex == e.OldIndex)) {
  1257. ListChangedEventArgs newEventArg = new ListChangedEventArgs(e.ListChangedType, e.NewIndex, new DataColumnPropertyDescriptor(col));
  1258. onListChanged(this, newEventArg);
  1259. }
  1260. else {
  1261. onListChanged(this, e);
  1262. }
  1263. }
  1264. if (null != propertyName) {
  1265. // empty string if more than 1 column changed
  1266. this[e.NewIndex].RaisePropertyChangedEvent(propertyName);
  1267. }
  1268. }
  1269. catch (Exception f) {
  1270. //
  1271. if (!Common.ADP.IsCatchableExceptionType(f)) {
  1272. throw;
  1273. }
  1274. ExceptionBuilder.TraceExceptionWithoutRethrow(f);
  1275. // ignore the exception
  1276. }
  1277. }
  1278. private void OnInitialized() {
  1279. if (onInitialized != null) {
  1280. onInitialized(this, EventArgs.Empty);
  1281. }
  1282. }
  1283. /// <devdoc>
  1284. /// <para>
  1285. /// Opens a <see cref='System.Data.DataView'/>.
  1286. /// </para>
  1287. /// </devdoc>
  1288. protected void Open() {
  1289. shouldOpen = true;
  1290. UpdateIndex();
  1291. dvListener.RegisterMetaDataEvents(this.table);
  1292. }
  1293. /// <devdoc>
  1294. /// <para>[To be supplied.]</para>
  1295. /// </devdoc>
  1296. protected void Reset() {
  1297. if (IsOpen) {
  1298. index.Reset();
  1299. }
  1300. }
  1301. internal void ResetRowViewCache() {
  1302. Dictionary<DataRow, DataRowView> rvc = new Dictionary<DataRow, DataRowView>(CountFromIndex, DataRowReferenceComparer.Default);
  1303. DataRowView drv;
  1304. if (null != index) {
  1305. // SQLBU 428961: Serious performance issue when creating DataView
  1306. // this improves performance by iterating of the index instead of computing record by index
  1307. RBTree<int>.RBTreeEnumerator iterator = index.GetEnumerator(0);
  1308. while (iterator.MoveNext()) {
  1309. DataRow row = table.recordManager[iterator.Current];
  1310. if (!rowViewCache.TryGetValue(row, out drv)) {
  1311. drv = new DataRowView(this, row);
  1312. }
  1313. rvc.Add(row, drv);
  1314. }
  1315. }
  1316. if (null != addNewRow) {
  1317. rowViewCache.TryGetValue(addNewRow, out drv);
  1318. Debug.Assert(null != drv, "didn't contain addNewRow");
  1319. rvc.Add(addNewRow, drv);
  1320. }
  1321. Debug.Assert(rvc.Count == CountFromIndex, "didn't add expected count");
  1322. this.rowViewCache = rvc;
  1323. }
  1324. internal void SetDataViewManager(DataViewManager dataViewManager) {
  1325. if (this.table == null)
  1326. throw ExceptionBuilder.CanNotUse();
  1327. if (this.dataViewManager != dataViewManager) {
  1328. if (dataViewManager != null)
  1329. dataViewManager.nViews--;
  1330. this.dataViewManager = dataViewManager;
  1331. if (dataViewManager != null) {
  1332. dataViewManager.nViews++;
  1333. DataViewSetting dataViewSetting = dataViewManager.DataViewSettings[table];
  1334. try {
  1335. // [....]: check that we will not do unnesasary operation here if dataViewSetting.Sort == this.Sort ...
  1336. applyDefaultSort = dataViewSetting.ApplyDefaultSort;
  1337. DataExpression newFilter = new DataExpression(table, dataViewSetting.RowFilter);
  1338. SetIndex(dataViewSetting.Sort, dataViewSetting.RowStateFilter, newFilter);
  1339. }
  1340. catch (Exception e) {
  1341. //
  1342. if (!Common.ADP.IsCatchableExceptionType(e)) {
  1343. throw;
  1344. }
  1345. ExceptionBuilder.TraceExceptionWithoutRethrow(e);
  1346. // ignore the exception
  1347. }
  1348. locked = true;
  1349. } else {
  1350. SetIndex("", DataViewRowState.CurrentRows, null);
  1351. }
  1352. }
  1353. }
  1354. internal virtual void SetIndex(string newSort, DataViewRowState newRowStates, IFilter newRowFilter) {
  1355. SetIndex2(newSort, newRowStates, newRowFilter, true);
  1356. }
  1357. internal void SetIndex2(string newSort, DataViewRowState newRowStates, IFilter newRowFilter, bool fireEvent) {
  1358. Bid.Trace("<ds.DataView.SetIndex|INFO> %d#, newSort='%ls', newRowStates=%d{ds.DataViewRowState}\n", ObjectID, newSort, (int)newRowStates);
  1359. this.sort = newSort;
  1360. this.recordStates = newRowStates;
  1361. this.rowFilter = newRowFilter;
  1362. Debug.Assert((0 == (DataViewRowState.ModifiedCurrent & newRowStates)) ||
  1363. (0 == (DataViewRowState.ModifiedOriginal & newRowStates)),
  1364. "asking DataViewRowState for both Original & Current records");
  1365. if (fEndInitInProgress)
  1366. return;
  1367. if (fireEvent) {
  1368. // old code path for virtual UpdateIndex
  1369. UpdateIndex(true);
  1370. }
  1371. else {
  1372. // new code path for RelatedView
  1373. Debug.Assert(null == _comparison, "RelatedView should not have a comparison function");
  1374. UpdateIndex(true, false);
  1375. }
  1376. if (null != findIndexes) {
  1377. Dictionary<string,Index> indexes = findIndexes;
  1378. findIndexes = null;
  1379. foreach(KeyValuePair<string,Index> entry in indexes) {
  1380. entry.Value.RemoveRef();
  1381. }
  1382. }
  1383. }
  1384. protected void UpdateIndex() {
  1385. UpdateIndex(false);
  1386. }
  1387. protected virtual void UpdateIndex(bool force) {
  1388. UpdateIndex(force, true);
  1389. }
  1390. internal void UpdateIndex(bool force, bool fireEvent) {
  1391. IntPtr hscp;
  1392. Bid.ScopeEnter(out hscp, "<ds.DataView.UpdateIndex|INFO> %d#, force=%d{bool}\n", ObjectID, force);
  1393. try {
  1394. if (open != shouldOpen || force) {
  1395. this.open = shouldOpen;
  1396. Index newIndex = null;
  1397. if (open) {
  1398. if (table != null) {
  1399. if (null != SortComparison)
  1400. {
  1401. // because an Index with with a Comparison<DataRow is not sharable, directly create the index here
  1402. newIndex = new Index(table, SortComparison, ((DataViewRowState)(int)recordStates), GetFilter());
  1403. // bump the addref from 0 to 1 to added to table index collection
  1404. // the bump from 1 to 2 will happen via DataViewListener.RegisterListChangedEvent
  1405. newIndex.AddRef();
  1406. }
  1407. else
  1408. {
  1409. newIndex = table.GetIndex(Sort, ((DataViewRowState)(int)recordStates), GetFilter());
  1410. }
  1411. }
  1412. }
  1413. if (index == newIndex) {
  1414. return;
  1415. }
  1416. DataTable _table = index != null ? index.Table : newIndex.Table;
  1417. if (index != null) {
  1418. this.dvListener.UnregisterListChangedEvent();
  1419. }
  1420. index = newIndex;
  1421. if (index != null) {
  1422. this.dvListener.RegisterListChangedEvent(index);
  1423. }
  1424. ResetRowViewCache();
  1425. if (fireEvent) {
  1426. OnListChanged(ResetEventArgs);
  1427. }
  1428. }
  1429. }
  1430. finally{
  1431. Bid.ScopeLeave(ref hscp);
  1432. }
  1433. }
  1434. internal void ChildRelationCollectionChanged(object sender, CollectionChangeEventArgs e) {
  1435. DataRelationPropertyDescriptor NullProp = null;
  1436. OnListChanged(
  1437. e.Action == CollectionChangeAction.Add ? new ListChangedEventArgs(ListChangedType.PropertyDescriptorAdded, new DataRelationPropertyDescriptor((System.Data.DataRelation)e.Element)) :
  1438. e.Action == CollectionChangeAction.Refresh ? new ListChangedEventArgs(ListChangedType.PropertyDescriptorChanged, NullProp):
  1439. e.Action == CollectionChangeAction.Remove ? new ListChangedEventArgs(ListChangedType.PropertyDescriptorDeleted, new DataRelationPropertyDescriptor((System.Data.DataRelation)e.Element)) :
  1440. /*default*/ null
  1441. );
  1442. }
  1443. internal void ParentRelationCollectionChanged(object sender, CollectionChangeEventArgs e) {
  1444. DataRelationPropertyDescriptor NullProp = null;
  1445. OnListChanged(
  1446. e.Action == CollectionChangeAction.Add ? new ListChangedEventArgs(ListChangedType.PropertyDescriptorAdded, new DataRelationPropertyDescriptor((System.Data.DataRelation)e.Element)) :
  1447. e.Action == CollectionChangeAction.Refresh ? new ListChangedEventArgs(ListChangedType.PropertyDescriptorChanged, NullProp):
  1448. e.Action == CollectionChangeAction.Remove ? new ListChangedEventArgs(ListChangedType.PropertyDescriptorDeleted, new DataRelationPropertyDescriptor((System.Data.DataRelation)e.Element)) :
  1449. /*default*/ null
  1450. );
  1451. }
  1452. protected virtual void ColumnCollectionChanged(object sender, CollectionChangeEventArgs e) {
  1453. DataColumnPropertyDescriptor NullProp = null;
  1454. OnListChanged(
  1455. e.Action == CollectionChangeAction.Add ? new ListChangedEventArgs(ListChangedType.PropertyDescriptorAdded, new DataColumnPropertyDescriptor((System.Data.DataColumn)e.Element)) :
  1456. e.Action == CollectionChangeAction.Refresh ? new ListChangedEventArgs(ListChangedType.PropertyDescriptorChanged, NullProp):
  1457. e.Action == CollectionChangeAction.Remove ? new ListChangedEventArgs(ListChangedType.PropertyDescriptorDeleted, new DataColumnPropertyDescriptor((System.Data.DataColumn)e.Element)) :
  1458. /*default*/ null
  1459. );
  1460. }
  1461. internal void ColumnCollectionChangedInternal(object sender, CollectionChangeEventArgs e) {
  1462. ColumnCollectionChanged(sender, e);
  1463. }
  1464. public DataTable ToTable() {
  1465. return ToTable(null, false, new string[0]);
  1466. }
  1467. public DataTable ToTable(string tableName){
  1468. return ToTable(tableName, false, new string[0]);
  1469. }
  1470. public DataTable ToTable(bool distinct, params string[] columnNames){
  1471. return ToTable(null, distinct, columnNames);
  1472. }
  1473. public DataTable ToTable(string tableName, bool distinct, params string[] columnNames){
  1474. Bid.Trace("<ds.DataView.ToTable|API> %d#, TableName='%ls', distinct=%d{bool}\n", ObjectID, tableName, distinct);
  1475. if (columnNames == null){
  1476. throw ExceptionBuilder.ArgumentNull("columnNames");
  1477. }
  1478. DataTable dt = new DataTable();
  1479. dt.Locale = this.table.Locale;
  1480. dt.CaseSensitive = this.table.CaseSensitive;
  1481. dt.TableName = ((null != tableName) ? tableName : this.table.TableName);
  1482. dt.Namespace = this.table.Namespace;
  1483. dt.Prefix = this.table.Prefix;
  1484. if (columnNames.Length == 0) {
  1485. columnNames = new string[Table.Columns.Count];
  1486. for (int i = 0; i < columnNames.Length; i++) {
  1487. columnNames[i] = Table.Columns[i].ColumnName;
  1488. }
  1489. }
  1490. int [] columnIndexes = new int[columnNames.Length];
  1491. List<object[]> rowlist = new List<object[]>();
  1492. for(int i = 0; i < columnNames.Length ; i++){
  1493. DataColumn dc = Table.Columns[columnNames[i]];
  1494. if (dc == null) {
  1495. throw ExceptionBuilder.ColumnNotInTheUnderlyingTable(columnNames[i], Table.TableName);
  1496. }
  1497. dt.Columns.Add(dc.Clone());
  1498. columnIndexes[i] = Table.Columns.IndexOf(dc);
  1499. }
  1500. foreach (DataRowView drview in this) {
  1501. object[] o = new object[columnNames.Length];
  1502. for (int j = 0; j < columnIndexes.Length; j++) {
  1503. o[j] = drview[columnIndexes[j]];
  1504. }
  1505. if ( !distinct || !RowExist(rowlist, o)) {
  1506. dt.Rows.Add(o);
  1507. rowlist.Add(o);
  1508. }
  1509. }
  1510. return dt;
  1511. }
  1512. private bool RowExist(List<object[]> arraylist, object[] objectArray) {
  1513. for (int i =0 ; i < arraylist.Count ; i++){
  1514. object[] rows = arraylist[i];
  1515. bool retval = true;
  1516. for (int j = 0; j < objectArray.Length; j++){
  1517. retval &= (rows[j].Equals(objectArray[j]));
  1518. }
  1519. if (retval)
  1520. return true;
  1521. }
  1522. return false;
  1523. }
  1524. /// <summary>
  1525. /// If <paramref name="view"/> is equivalent to the the current view with regards to all properties.
  1526. /// <see cref="RowFilter"/> and <see cref="Sort"/> may differ by <see cref="StringComparison.OrdinalIgnoreCase"/>.
  1527. /// </summary>
  1528. public virtual bool Equals(DataView view) {
  1529. if ((null == view) ||
  1530. this.Table != view.Table ||
  1531. this.Count != view.Count ||
  1532. (string.Compare(this.RowFilter, view.RowFilter, StringComparison.OrdinalIgnoreCase) != 0) || // case insensitive
  1533. (string.Compare(this.Sort, view.Sort, StringComparison.OrdinalIgnoreCase) != 0) || // case insensitive
  1534. !Object.ReferenceEquals(SortComparison, view.SortComparison) ||
  1535. !Object.ReferenceEquals(RowPredicate, view.RowPredicate) ||
  1536. this.RowStateFilter != view.RowStateFilter ||
  1537. this.DataViewManager != view.DataViewManager||
  1538. this.AllowDelete != view.AllowDelete||
  1539. this.AllowNew != view.AllowNew||
  1540. this.AllowEdit != view.AllowEdit )
  1541. return false;
  1542. return true;
  1543. }
  1544. internal int ObjectID {
  1545. get {
  1546. return _objectID;
  1547. }
  1548. }
  1549. }
  1550. }