Welcome to mirror list, hosted at ThFree Co, Russian Federation.

DataRowView.cs « Data « System « System.Data « referencesource « class « mcs - github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 0597645639ac3af74b1ae9d93c0912e71d6ce1b3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
//------------------------------------------------------------------------------
// <copyright file="DataRowView.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------

namespace System.Data {
    using System.Diagnostics;
    using System.ComponentModel;

    public class DataRowView : ICustomTypeDescriptor, System.ComponentModel.IEditableObject, System.ComponentModel.IDataErrorInfo, System.ComponentModel.INotifyPropertyChanged {

        private readonly DataView dataView;
        private readonly DataRow _row;
        private bool delayBeginEdit;

        private static PropertyDescriptorCollection zeroPropertyDescriptorCollection = new PropertyDescriptorCollection(null);

        /// <summary>
        /// When the PropertyChanged event happens, it must happen on the same DataRowView reference.
        /// This is so a generic event handler like Windows Presentation Foundation can redirect as appropriate.
        /// Having DataView.Equals is not sufficient for WPF, because two different instances may be equal but not equivalent.
        /// For DataRowView, if two instances are equal then they are equivalent.
        /// </summary>
        private System.ComponentModel.PropertyChangedEventHandler  onPropertyChanged;

        internal DataRowView(DataView dataView, DataRow row)
        {
            this.dataView = dataView;
            this._row = row;
        }

        /// <remarks>
        /// Checks for same reference instead of equivalent <see cref="DataView"/> or <see cref="Row"/>.
        /// 
        /// Necessary for ListChanged event handlers to use data structures that use the default to
        /// <see cref="Object.Equals(Object)"/> instead of <see cref="Object.ReferenceEquals"/>
        /// to understand if they need to add a <see cref="PropertyChanged"/> event handler.
        /// </remarks>
        /// <returns><see cref="Object.ReferenceEquals"/></returns>
        public override bool Equals(object other) {
            return Object.ReferenceEquals(this, other);
        }

        /// <returns>Hashcode of <see cref="Row"/></returns>
        public override Int32 GetHashCode() {
            // Everett compatability, must return hashcode for DataRow
            // this does prevent using this object in collections like Hashtable
            // which use the hashcode as an immutable value to identify this object
            // user could/should have used the DataRow property instead of the hashcode
            return Row.GetHashCode();
        }

        public DataView DataView {
            get {
                return dataView;
            }
        }

        internal int ObjectID {
            get { return _row.ObjectID; }
        }

        /// <summary>Gets or sets a value in specified column.</summary>
        /// <param name="ndx">Specified column index.</param>
        /// <remarks>Uses either <see cref="DataRowVersion.Default"/> or <see cref="DataRowVersion.Original"/> to access <see cref="Row"/></remarks>
        /// <exception cref="DataException"><see cref="System.Data.DataView.get_AllowEdit"/> when setting a value.</exception>
        /// <exception cref="IndexOutOfRangeException"><see cref="DataColumnCollection.get_Item(int)"/></exception>
        public object this[int ndx] {
            get {
                return Row[ndx, RowVersionDefault];
            }
            set {
                if (!dataView.AllowEdit && !IsNew) {
                    throw ExceptionBuilder.CanNotEdit();
                }
                SetColumnValue(dataView.Table.Columns[ndx], value);
            }
        }

        /// <summary>Gets the specified column value or related child view or sets a value in specified column.</summary>
        /// <param name="property">Specified column or relation name when getting.  Specified column name when setting.</param>
        /// <exception cref="ArgumentException"><see cref="DataColumnCollection.get_Item(string)"/> when <paramref name="property"/> is ambigous.</exception>
        /// <exception cref="ArgumentException">Unmatched <paramref name="property"/> when getting a value.</exception>
        /// <exception cref="DataException">Unmatched <paramref name="property"/> when setting a value.</exception>
        /// <exception cref="DataException"><see cref="System.Data.DataView.get_AllowEdit"/> when setting a value.</exception>
        public object this[string property] {
            get {
                DataColumn column = dataView.Table.Columns[property];
                if (null != column) {
                    return Row[column, RowVersionDefault];
                }
                else if (dataView.Table.DataSet != null && dataView.Table.DataSet.Relations.Contains(property)) {
                    return CreateChildView(property);
                }
                throw ExceptionBuilder.PropertyNotFound(property, dataView.Table.TableName);
            }
            set {
                DataColumn column = dataView.Table.Columns[property];
                if (null == column) {
                    throw ExceptionBuilder.SetFailed(property);
                }
                if (!dataView.AllowEdit && !IsNew) {
                    throw ExceptionBuilder.CanNotEdit();
                }
                SetColumnValue(column, value);
            }
        }

        // IDataErrorInfo stuff
        string System.ComponentModel.IDataErrorInfo.this[string colName] {
            get {
                return Row.GetColumnError(colName);
            }
        }

        string System.ComponentModel.IDataErrorInfo.Error {
            get {
                return Row.RowError;
            }
        }
        
        /// <summary>
        /// Gets the current version description of the <see cref="DataRow"/>
        /// in relation to <see cref="System.Data.DataView.get_RowStateFilter"/>
        /// </summary>
        /// <returns>Either <see cref="DataRowVersion.Current"/> or <see cref="DataRowVersion.Original"/></returns>
        public DataRowVersion RowVersion {
            get {
                return (RowVersionDefault & ~DataRowVersion.Proposed);
            }
        }

        /// <returns>Either <see cref="DataRowVersion.Default"/> or <see cref="DataRowVersion.Original"/></returns>
        private DataRowVersion RowVersionDefault {
            get {
                return Row.GetDefaultRowVersion(dataView.RowStateFilter);
            }
        }

        internal int GetRecord() {
            return Row.GetRecordFromVersion(RowVersionDefault);
        }

        internal bool HasRecord() {
            return Row.HasVersion(RowVersionDefault);
        }

        internal object GetColumnValue(DataColumn column) {
            return Row[column, RowVersionDefault];
        }

        internal void SetColumnValue(DataColumn column, object value) {
            if (delayBeginEdit) {
                delayBeginEdit = false;
                Row.BeginEdit();
            }
            if (DataRowVersion.Original == RowVersionDefault) {
                throw ExceptionBuilder.SetFailed(column.ColumnName);
            }
            Row[column] = value;
        }

        /// <summary>
        /// Returns a <see cref="System.Data.DataView"/>
        /// for the child <see cref="System.Data.DataTable"/>
        /// with the specified <see cref="System.Data.DataRelation"/>.
        /// </summary>
        /// <param name="relation">Specified <see cref="System.Data.DataRelation"/>.</param>
        /// <exception cref="ArgumentException">null or mismatch between <paramref name="relation"/> and <see cref="System.Data.DataView.get_Table"/>.</exception>
        public DataView CreateChildView(DataRelation relation, bool followParent) {
            if (relation == null || relation.ParentKey.Table != DataView.Table) {
                throw ExceptionBuilder.CreateChildView();
            }
            RelatedView childView;
            if (!followParent) {
                int record = GetRecord();
                object[] values = relation.ParentKey.GetKeyValues(record);
                childView = new RelatedView(relation.ChildColumnsReference, values);
            }
            else {
                childView = new RelatedView(this, relation.ParentKey, relation.ChildColumnsReference);
            }
            childView.SetIndex("", DataViewRowState.CurrentRows, null); // finish construction via RelatedView.SetIndex
            childView.SetDataViewManager(DataView.DataViewManager);
            return childView;
        }


        public DataView CreateChildView(DataRelation relation) {
            return CreateChildView(relation, followParent: false);
        }


        /// <summary><see cref="CreateChildView(DataRelation)"/></summary>
        /// <param name="relationName">Specified <see cref="System.Data.DataRelation"/> name.</param>
        /// <exception cref="ArgumentException">Unmatched <paramref name="relationName"/>.</exception>
        public DataView CreateChildView(string relationName, bool followParent) {
            return CreateChildView(DataView.Table.ChildRelations[relationName], followParent);
        }

        public DataView CreateChildView(string relationName) {
            return CreateChildView(relationName, followParent: false);
        }

        public DataRow Row {
            get {
                return _row;
            }
        }

        public void BeginEdit() {
            delayBeginEdit = true;
        }

        public void CancelEdit() {
            DataRow tmpRow = Row;
            if (IsNew) {
                dataView.FinishAddNew(false);
            }
            else {
                tmpRow.CancelEdit();
            }
            delayBeginEdit = false;
        }

        public void EndEdit() {
            if (IsNew) {
                dataView.FinishAddNew(true);
            }
            else {
                Row.EndEdit();
            }
            delayBeginEdit = false;
        }

        public bool IsNew {
            get {
                return (_row == dataView.addNewRow);
            }
        }

        public bool IsEdit {
            get {
                return (
                    Row.HasVersion(DataRowVersion.Proposed) ||  // It was edited or
                    delayBeginEdit);                            // DataRowView.BegingEdit() was called, but not edited yet.
            }
        }

        public void Delete() {
            dataView.Delete(Row);
        }

        #region ICustomTypeDescriptor

        AttributeCollection ICustomTypeDescriptor.GetAttributes() {
            return new AttributeCollection((Attribute[])null);
        }

        string ICustomTypeDescriptor.GetClassName() {
            return null;
        }

        string ICustomTypeDescriptor.GetComponentName() {
            return null;
        }

        TypeConverter ICustomTypeDescriptor.GetConverter() {
            return null;
        }

        EventDescriptor ICustomTypeDescriptor.GetDefaultEvent() {
            return null;
        }

        PropertyDescriptor ICustomTypeDescriptor.GetDefaultProperty() {
            return null;
        }

        object ICustomTypeDescriptor.GetEditor(Type editorBaseType) {
            return null;
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents() {
            return new EventDescriptorCollection(null);
        }

        EventDescriptorCollection ICustomTypeDescriptor.GetEvents(Attribute[] attributes) {
            return new EventDescriptorCollection(null);
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties() {
            return((ICustomTypeDescriptor)this).GetProperties(null);
        }

        PropertyDescriptorCollection ICustomTypeDescriptor.GetProperties(Attribute[] attributes) {
            return (dataView.Table != null ? dataView.Table.GetPropertyDescriptorCollection(attributes) : zeroPropertyDescriptorCollection);
        }

        object ICustomTypeDescriptor.GetPropertyOwner(PropertyDescriptor pd) {
            return this;
        }

        #endregion

        public event PropertyChangedEventHandler PropertyChanged {
            add {
                onPropertyChanged += value;
            }
            remove {
                onPropertyChanged -= value;
            }

        }

        internal void RaisePropertyChangedEvent (string propName){
            // Do not try catch, we would mask users bugs. if they throw we would catch
            if (onPropertyChanged != null) {
                onPropertyChanged (this, new PropertyChangedEventArgs(propName));
            }
        }
    }
}