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
|
//------------------------------------------------------------------------------
// <copyright file="BaseDataBoundControl.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.UI.WebControls {
using System;
using System.Collections;
using System.ComponentModel;
using System.Web.Util;
/// <summary>
/// A BaseDataBoundControl is bound to a data source and generates its
/// user interface (or child control hierarchy typically), by enumerating
/// the items in the data source it is bound to.
/// BaseDataBoundControl is an abstract base class that defines the common
/// characteristics of all controls that use a list as a data source, such as
/// DataGrid, DataBoundTable, ListBox etc. It encapsulates the logic
/// of how a data-bound control binds to collections or DataControl instances.
/// </summary>
[
Designer("System.Web.UI.Design.WebControls.BaseDataBoundControlDesigner, " + AssemblyRef.SystemDesign),
DefaultProperty("DataSourceID")
]
public abstract class BaseDataBoundControl : WebControl {
private static readonly object EventDataBound = new object();
private object _dataSource;
private bool _requiresDataBinding;
private bool _inited;
private bool _preRendered;
private bool _requiresBindToNull;
private bool _throwOnDataPropertyChange;
/// <summary>
/// The data source to bind to. This allows a BaseDataBoundControl to bind
/// to arbitrary lists of data items.
/// </summary>
[
Bindable(true),
DefaultValue(null),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Themeable(false),
WebCategory("Data"),
WebSysDescription(SR.BaseDataBoundControl_DataSource),
]
public virtual object DataSource {
get {
return _dataSource;
}
set {
if (value != null) {
ValidateDataSource(value);
}
_dataSource = value;
OnDataPropertyChanged();
}
}
/// <summary>
/// The ID of the DataControl that this control should use to retrieve
/// its data source. When the control is bound to a DataControl, it
/// can retrieve a data source instance on-demand, and thereby attempt
/// to work in auto-DataBind mode.
/// </summary>
[
DefaultValue(""),
Themeable(false),
WebCategory("Data"),
WebSysDescription(SR.BaseDataBoundControl_DataSourceID)
]
public virtual string DataSourceID {
get {
object o = ViewState["DataSourceID"];
if (o != null) {
return (string)o;
}
return String.Empty;
}
set {
if (String.IsNullOrEmpty(value) && !String.IsNullOrEmpty(DataSourceID)) {
_requiresBindToNull = true;
}
ViewState["DataSourceID"] = value;
OnDataPropertyChanged();
}
}
protected bool Initialized {
get {
return _inited;
}
}
/// <summary>
/// Returns true if the DataBoundControl uses Select/Update/Delete/Insert Methods for databinding.
/// Implementation on BaseDataBoundControl returns false.
/// Override in child classes which support the above two properties.
/// </summary>
protected virtual bool IsUsingModelBinders {
get {
return false;
}
}
/// <summary>
/// This returns true only if the DataBoundControl is using a DataSourceID.
/// Use the IsDataBindingAutomatic property to determine if the data bound control's data binding is
/// automatic. The data binding is automatic if the control is using a DataSourceID or if control
/// uses Select/Update/Delete/Insert Methods for data binding.
/// </summary>
protected bool IsBoundUsingDataSourceID {
get {
return (DataSourceID.Length > 0);
}
}
/// <summary>
/// This property is used by FormView/GridView/DetailsView/ListView in the following scenarios.
/// 1. Perform an auto data bind (Listen to OnDataSourceViewChanged event and set RequiresDataBinding to true)
/// 2. Calling the data source view operations
/// 3. Raising exceptions when there is no DataSourceId (i.e., a DataSource is in use) and an event for Data Operation is not handled
/// 4. Raising the ModeChanged events for DataControls
/// This property is true if the control is bound using a DataSourceId or when the control participates in Model Binding.
/// </summary>
protected internal bool IsDataBindingAutomatic {
get {
return IsBoundUsingDataSourceID || IsUsingModelBinders;
}
}
public override bool SupportsDisabledAttribute {
get {
return RenderingCompatibility < VersionUtil.Framework40;
}
}
protected bool RequiresDataBinding {
get {
return _requiresDataBinding;
}
set {
// if we have to play catch-up here because we've already PreRendered, call EnsureDataBound
if (value && _preRendered && IsDataBindingAutomatic && Page != null && !Page.IsCallback) {
_requiresDataBinding = true;
EnsureDataBound();
}
else {
_requiresDataBinding = value;
}
}
}
[
WebCategory("Data"),
WebSysDescription(SR.BaseDataBoundControl_OnDataBound)
]
public event EventHandler DataBound {
add {
Events.AddHandler(EventDataBound, value);
}
remove {
Events.RemoveHandler(EventDataBound, value);
}
}
protected void ConfirmInitState() {
_inited = true; // do this in OnLoad in case we were added to the page after Page.OnPreLoad
}
/// <summary>
/// Overriden by BaseDataBoundControl to use its properties to determine the real
/// data source that the control should bind to. It then clears the existing
/// control hierarchy, and calls CreateChildControls to create a new control
/// hierarchy based on the resolved data source.
/// The implementation resolves various data source related properties to
/// arrive at the appropriate IEnumerable implementation to use as the real
/// data source.
/// When resolving data sources, the DataSourceID takes highest precedence.
/// If DataSourceID is not set, the value of the DataSource property is used.
/// In this second alternative, DataMember is used to extract the appropriate
/// list if the control has been handed an IListSource as a data source.
///
/// Data bound controls should override PerformDataBinding instead
/// of DataBind. If DataBind if overridden, the OnDataBinding and OnDataBound events will
/// fire in the wrong order. However, for backwards compat on ListControl and AdRotator, we
/// can't seal this method. It is sealed on all new BaseDataBoundControl-derived controls.
/// </summary>
public override void DataBind() {
// Don't databind when the control is in the designer but not top-level
if (DesignMode) {
IDictionary designModeState = GetDesignModeState();
if (((designModeState == null) || (designModeState["EnableDesignTimeDataBinding"] == null))
&& (Site == null)) {
return;
}
}
PerformSelect();
}
protected virtual void EnsureDataBound() {
try {
_throwOnDataPropertyChange = true;
if (RequiresDataBinding && (IsDataBindingAutomatic || _requiresBindToNull)) {
DataBind();
_requiresBindToNull = false;
}
}
finally {
_throwOnDataPropertyChange = false;
}
}
internal void InternalEnsureDataBound() {
EnsureDataBound();
}
protected virtual void OnDataBound(EventArgs e) {
EventHandler handler = Events[EventDataBound] as EventHandler;
if (handler != null) {
handler(this, e);
}
}
/// <devdoc>
/// This method is called when DataMember, DataSource, or DataSourceID is changed.
/// </devdoc>
protected virtual void OnDataPropertyChanged() {
if (_throwOnDataPropertyChange) {
throw new HttpException(SR.GetString(SR.DataBoundControl_InvalidDataPropertyChange, ID));
}
if (_inited) {
RequiresDataBinding = true;
}
}
protected internal override void OnInit(EventArgs e) {
base.OnInit(e);
if (Page != null) {
Page.PreLoad += new EventHandler(this.OnPagePreLoad);
if (!IsViewStateEnabled && Page.IsPostBack) {
RequiresDataBinding = true;
}
}
}
protected virtual void OnPagePreLoad(object sender, EventArgs e) {
_inited = true;
if (Page != null) {
Page.PreLoad -= new EventHandler(this.OnPagePreLoad);
}
}
protected internal override void OnPreRender(EventArgs e) {
_preRendered = true;
EnsureDataBound();
base.OnPreRender(e);
}
/// <summary>
/// Override to control how the data is selected and the control is databound.
/// </summary>
protected abstract void PerformSelect();
protected abstract void ValidateDataSource(object dataSource);
}
}
|