File: HierarchicalDataBoundControl.cs

package info (click to toggle)
mono 6.8.0.105%2Bdfsg-3.3
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 1,284,512 kB
  • sloc: cs: 11,172,132; xml: 2,850,069; ansic: 671,653; cpp: 122,091; perl: 59,366; javascript: 30,841; asm: 22,168; makefile: 20,093; sh: 15,020; python: 4,827; pascal: 925; sql: 859; sed: 16; php: 1
file content (237 lines) | stat: -rw-r--r-- 10,733 bytes parent folder | download | duplicates (7)
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
//------------------------------------------------------------------------------
// <copyright file="HierarchicalDataBoundControl.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

namespace System.Web.UI.WebControls {
    using System.Collections;
    using System.ComponentModel;
    using System.Web.Util;
    using System.Web.UI.WebControls.Adapters;


    [
    Designer("System.Web.UI.Design.WebControls.HierarchicalDataBoundControlDesigner, " + AssemblyRef.SystemDesign)
    ]
    public abstract class HierarchicalDataBoundControl : BaseDataBoundControl {

        private IHierarchicalDataSource _currentHierarchicalDataSource;
        private bool _currentDataSourceIsFromControl;
        private bool _currentDataSourceValid;
        private bool _pagePreLoadFired;
        
        private const string DataBoundViewStateKey = "_!DataBound";


        /// <internalonly />
        [IDReferenceProperty(typeof(HierarchicalDataSourceControl))]
        public override string DataSourceID {
            get {
                return base.DataSourceID;
            }
            set {
                base.DataSourceID = value;
            }
        }

        /// <devdoc>
        /// Connects this hierarchical data bound control to the appropriate
        /// HierarchicalDataSource and hooks up the appropriate event listener
        /// for the DataSourceChanged event. The return value is the new data source
        /// (if any) that was connected to. An exception is thrown if there is
        /// a problem finding the requested data source.
        /// </devdoc>
        private IHierarchicalDataSource ConnectToHierarchicalDataSource() {
            if (_currentDataSourceValid && !DesignMode) {
                // Ensure that both DataSourceID as well as DataSource are not set at the same time
                if (!_currentDataSourceIsFromControl && DataSourceID != null && DataSourceID.Length != 0) {
                    throw new InvalidOperationException(SR.GetString(SR.DataControl_MultipleDataSources, ID));
                }
                // If the current view is correct, there is no need to reconnect
                return _currentHierarchicalDataSource;
            }

            // Disconnect from old view, if necessary
            if ((_currentHierarchicalDataSource != null) && (_currentDataSourceIsFromControl)) {
                // We only care about this event if we are bound through the DataSourceID property
                _currentHierarchicalDataSource.DataSourceChanged -= new EventHandler(OnDataSourceChanged);
            }

            // Connect to new view
            _currentHierarchicalDataSource = GetDataSource();
            _currentDataSourceIsFromControl = IsBoundUsingDataSourceID;

            if (_currentHierarchicalDataSource == null) {
                // HierarchicalDataSource control was not found, construct a temporary data source to wrap the data
                _currentHierarchicalDataSource = new ReadOnlyHierarchicalDataSource(DataSource);
            }
            else {
                // Ensure that both DataSourceID as well as DataSource are not set at the same time
                if (DataSource != null) {
                    throw new InvalidOperationException(SR.GetString(SR.DataControl_MultipleDataSources, ID));
                }
            }

            _currentDataSourceValid = true;
            
            if ((_currentHierarchicalDataSource != null) && (_currentDataSourceIsFromControl)) {
                // We only care about this event if we are bound through the DataSourceID property
                _currentHierarchicalDataSource.DataSourceChanged += new EventHandler(OnDataSourceChanged);
            }

            return _currentHierarchicalDataSource;
        }


        /// <devdoc>
        /// Gets the HierarchicalDataSourceView of the IHierarchicalDataSource
        /// that this control is bound to, if any.
        /// </devdoc>
        protected virtual HierarchicalDataSourceView GetData(string viewPath) {
            string currentViewPath = viewPath;
            IHierarchicalDataSource ds = ConnectToHierarchicalDataSource();
            Debug.Assert(_currentDataSourceValid);

            Debug.Assert(ds != null);

            // IHierarchicalDataSource was found, extract the appropriate view and return it
            HierarchicalDataSourceView view = ds.GetHierarchicalView(currentViewPath);
            if (view == null) {
                throw new InvalidOperationException(SR.GetString(SR.HierarchicalDataControl_ViewNotFound, ID));
            }
            return view;
        }


        /// <devdoc>
        /// Gets the IHierarchicalDataSource that this control is bound to, if any.
        /// </devdoc>
        protected virtual IHierarchicalDataSource GetDataSource() {
            if (!DesignMode && _currentDataSourceValid && (_currentHierarchicalDataSource != null)) {
                return _currentHierarchicalDataSource;
            }

            IHierarchicalDataSource ds = null;
            string dataSourceID = DataSourceID;

            if (dataSourceID.Length != 0) {
                // Try to find a DataSource control with the ID specified in DataSourceID
                Control control = DataBoundControlHelper.FindControl(this, dataSourceID);
                if (control == null) {
                    throw new HttpException(SR.GetString(SR.HierarchicalDataControl_DataSourceDoesntExist, ID, dataSourceID));
                }
                ds = control as IHierarchicalDataSource;
                if (ds == null) {
                    throw new HttpException(SR.GetString(SR.HierarchicalDataControl_DataSourceIDMustBeHierarchicalDataControl, ID, dataSourceID));
                }
            }
            return ds;
        }

        protected void MarkAsDataBound() {
            ViewState[DataBoundViewStateKey] = true;
        }
        

        protected override void OnDataPropertyChanged() {
            _currentDataSourceValid = false;
            base.OnDataPropertyChanged();
        }


        /// <devdoc>
        ///  This method is called when the IHierarchicalDataSource raises a DataSourceChanged event.
        /// </devdoc>
        protected virtual void OnDataSourceChanged(object sender, EventArgs e) {
            RequiresDataBinding = true;
        }
        

        protected internal override void OnLoad(EventArgs e) {
            ConfirmInitState();
            ConnectToHierarchicalDataSource();

            if (Page != null && !_pagePreLoadFired && ViewState[DataBoundViewStateKey] == null) {
                // If the control was added after PagePreLoad, we still need to databind it because it missed its
                // first change in PagePreLoad.  If this control was created by a call to a parent control's DataBind
                // in Page_Load (with is relatively common), this control will already have been databound even
                // though pagePreLoad never fired and the page isn't a postback.
                if (!Page.IsPostBack) {
                    RequiresDataBinding = true;
                }
                // If the control was added to the page after page.PreLoad, we'll never get the event and we'll
                // never databind the control.  So if we're catching up and Load happens but PreLoad never happened,
                // call DataBind.  This may make the control get databound twice if the user called DataBind on the control
                // directly in Page.OnLoad, but better to bind twice than never to bind at all.
                else if (IsViewStateEnabled) {
                    RequiresDataBinding = true;
                }
            }
            
            base.OnLoad(e);
        }

        protected override void OnPagePreLoad(object sender, EventArgs e) {
            base.OnPagePreLoad(sender, e);
            
            if (Page != null) {
                // Setting RequiresDataBinding to true in OnLoad is too late because the OnLoad page event
                // happens before the control.OnLoad method gets called.  So a page_load handler on the page
                // that calls DataBind won't prevent DataBind from getting called again in PreRender.
                if (!Page.IsPostBack) {
                    RequiresDataBinding = true;
                }
                // If this is a postback and viewstate is enabled, but we have never bound the control
                // before, it is probably because its visibility was changed in the postback.  In this
                // case, we need to bind the control or it will never appear.  This is a common scenario
                // for Wizard and MultiView.
                else if (IsViewStateEnabled && ViewState[DataBoundViewStateKey] == null) {
                    RequiresDataBinding = true;
                }
            }
            _pagePreLoadFired = true;
        }
        

        /// <devdoc>
        ///  This method should be overridden by databound controls to perform their databinding.
        ///  Overriding this method instead of DataBind() will allow the DataBound control developer
        ///  to not worry about DataBinding events to be called in the right order.
        /// </devdoc>
        protected internal virtual void PerformDataBinding() {
        }

        /// <summary>
        ///  Issues an asynchronous request for data to the data source using the arguments from CreateDataSourceSelectArguments.
        /// </summary>
        protected override void PerformSelect() {
            OnDataBinding(EventArgs.Empty);
            if (AdapterInternal != null) {
                HierarchicalDataBoundControlAdapter hierarchicalAdapter = AdapterInternal as HierarchicalDataBoundControlAdapter;
                if(hierarchicalAdapter != null) {
                    hierarchicalAdapter.PerformDataBinding();
                }
                else {
                    PerformDataBinding();
                }
            }
            else {
                PerformDataBinding();
            }
            RequiresDataBinding = false;
            MarkAsDataBound();
            OnDataBound(EventArgs.Empty);
        }
        

        protected override void ValidateDataSource(object dataSource) {
            if ((dataSource == null) ||
                (dataSource is IHierarchicalEnumerable) ||
                (dataSource is IHierarchicalDataSource)) {
                return;
            }
            throw new InvalidOperationException(SR.GetString(SR.HierarchicalDataBoundControl_InvalidDataSource));
        }
    }
}