|
//------------------------------------------------------------------------------
// <copyright file="UpdatePanel.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
namespace System.Web.UI {
using System;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.Drawing.Design;
using System.Globalization;
using System.IO;
using System.Web;
using System.Web.UI;
using System.Web.Resources;
using System.Web.Util;
using Debug = System.Diagnostics.Debug;
[
DefaultProperty("Triggers"),
Designer("System.Web.UI.Design.UpdatePanelDesigner, " + AssemblyRef.SystemWebExtensionsDesign),
ParseChildren(true),
PersistChildren(false),
ToolboxBitmap(typeof(EmbeddedResourceFinder), "System.Web.Resources.UpdatePanel.bmp")
]
public class UpdatePanel : Control, IAttributeAccessor, IUpdatePanel {
private const string UpdatePanelToken = "updatePanel";
private new IPage _page;
private IScriptManagerInternal _scriptManager;
private AttributeCollection _attributes;
private bool _childrenAsTriggers = true;
private ITemplate _contentTemplate;
private Control _contentTemplateContainer;
private bool _asyncPostBackMode;
private bool _asyncPostBackModeInitialized;
private UpdatePanelUpdateMode _updateMode = UpdatePanelUpdateMode.Always;
private bool _rendered;
private bool _explicitUpdate;
private UpdatePanelRenderMode _renderMode = UpdatePanelRenderMode.Block;
private UpdatePanelTriggerCollection _triggers;
// Keep an explicit check whether the panel registered with ScriptManager. Sometimes
// OnInit is not called on the panel, so then OnUnload gets called and you get an
// exception. This can happen if an unhandled exception happened on the page before Init
// and the page unloads.
private bool _panelRegistered;
public UpdatePanel() {
}
internal UpdatePanel(IScriptManagerInternal scriptManager, IPage page) {
_scriptManager = scriptManager;
_page = page;
}
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
WebSysDescription(SR.WebControl_Attributes)
]
public AttributeCollection Attributes {
get {
if (_attributes == null) {
StateBag bag = new StateBag(true /* ignoreCase */);
_attributes = new AttributeCollection(bag);
}
return _attributes;
}
}
[
ResourceDescription("UpdatePanel_ChildrenAsTriggers"),
Category("Behavior"),
DefaultValue(true),
]
public bool ChildrenAsTriggers {
get {
return _childrenAsTriggers;
}
set {
_childrenAsTriggers = value;
}
}
[
Browsable(false),
PersistenceMode(PersistenceMode.InnerProperty),
TemplateInstance(TemplateInstance.Single),
]
public ITemplate ContentTemplate {
get {
return _contentTemplate;
}
set {
if (!DesignMode && _contentTemplate != null) {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.UpdatePanel_CannotSetContentTemplate, ID));
}
_contentTemplate = value;
if (_contentTemplate != null) {
// DevDiv 79989: Instantiate the template immediately so that the controls are available as soon as possible
CreateContents();
}
}
}
public sealed override ControlCollection Controls {
get {
// We override and seal this property because we have very special semantics
// on the behavior of this property and the type of ControlCollection we create.
return base.Controls;
}
}
[
Browsable(false),
]
public Control ContentTemplateContainer {
get {
if (_contentTemplateContainer == null) {
_contentTemplateContainer = CreateContentTemplateContainer();
AddContentTemplateContainer();
}
return _contentTemplateContainer;
}
}
[
Browsable(false),
]
public bool IsInPartialRendering {
get {
return _asyncPostBackMode;
}
}
private IPage IPage {
get {
if (_page != null) {
return _page;
}
else {
Page page = Page;
if (page == null) {
throw new InvalidOperationException(AtlasWeb.Common_PageCannotBeNull);
}
return new PageWrapper(page);
}
}
}
protected internal virtual bool RequiresUpdate {
get {
if (_explicitUpdate || (UpdateMode == UpdatePanelUpdateMode.Always)) {
return true;
}
if ((_triggers == null) || (_triggers.Count == 0)) {
return false;
}
return _triggers.HasTriggered();
}
}
[
ResourceDescription("UpdatePanel_RenderMode"),
Category("Layout"),
DefaultValue(UpdatePanelRenderMode.Block),
]
public UpdatePanelRenderMode RenderMode {
get {
return _renderMode;
}
set {
if (value < UpdatePanelRenderMode.Block || value > UpdatePanelRenderMode.Inline) {
throw new ArgumentOutOfRangeException("value");
}
_renderMode = value;
}
}
internal IScriptManagerInternal ScriptManager {
get {
if (_scriptManager == null) {
Page page = Page;
if (page == null) {
throw new InvalidOperationException(AtlasWeb.Common_PageCannotBeNull);
}
_scriptManager = UI.ScriptManager.GetCurrent(page);
if (_scriptManager == null) {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.Common_ScriptManagerRequired, ID));
}
}
return _scriptManager;
}
}
[
Category("Behavior"),
DefaultValue(null),
Editor("System.Web.UI.Design.UpdatePanelTriggerCollectionEditor, " +
AssemblyRef.SystemWebExtensionsDesign, typeof(UITypeEditor)),
ResourceDescription("UpdatePanel_Triggers"),
PersistenceMode(PersistenceMode.InnerProperty),
MergableProperty(false),
]
public UpdatePanelTriggerCollection Triggers {
get {
if (_triggers == null) {
// NOTE: This is not view state managed, because the update panel trigger
// collection needs to be ready by InitComplete (so that
// Initialize of all triggers gets called at init time), which
// implies that the trigger collection cannot be modified
// beyond what was set up declaratively.
_triggers = new UpdatePanelTriggerCollection(this);
}
return _triggers;
}
}
[
ResourceDescription("UpdatePanel_UpdateMode"),
Category("Behavior"),
DefaultValue(UpdatePanelUpdateMode.Always),
]
public UpdatePanelUpdateMode UpdateMode {
get {
return _updateMode;
}
set {
if (value < UpdatePanelUpdateMode.Always || value > UpdatePanelUpdateMode.Conditional) {
throw new ArgumentOutOfRangeException("value");
}
_updateMode = value;
}
}
private SingleChildControlCollection ChildControls {
get {
SingleChildControlCollection singleChildCollection = Controls as SingleChildControlCollection;
Debug.Assert(singleChildCollection != null, "The Controls property did not return the expected control collection instance.");
return singleChildCollection;
}
}
private void AddContentTemplateContainer() {
// This will call an internal method to specially add the
// ContentTemplateContainer to the control tree safely.
ChildControls.AddSingleChild(_contentTemplateContainer);
}
internal void ClearContent() {
Debug.Assert(DesignMode, "ClearContent should only be used in DesignMode.");
// DevDiv Bugs 135848:
// Called from UpdatePanelDesigner to clear control tree when
// GetDesignTimeHtml(DesignerRegionCollection regions) is called, necessary to avoid
// duplicate controls being created at design time. See comment in UpdatePanelDesigner.
ContentTemplateContainer.Controls.Clear();
_contentTemplateContainer = null;
ChildControls.ClearInternal();
}
private void CreateContents() {
if (DesignMode) {
// Clear out old stuff
ClearContent();
}
// The ContentTemplateContainer may have already been created by someone due to
// some dynamic access. If the container already exists and there is a ContentTemplate,
// we will instantiate into it.
if (_contentTemplateContainer == null) {
_contentTemplateContainer = CreateContentTemplateContainer();
// The controls inside the template are instantiated into
// a dummy container to ensure that they all do lifecycle catchup
// at the same time (i.e. Init1, Init2, Load1, Load2) as opposed to
// one after another (i.e. Init1, Load1, Init2, Load2).
if (_contentTemplate != null) {
_contentTemplate.InstantiateIn(_contentTemplateContainer);
}
AddContentTemplateContainer();
}
else if (_contentTemplate != null) {
// Someone already created a ContentTemplateContainer, instantiate into it
_contentTemplate.InstantiateIn(_contentTemplateContainer);
}
}
protected virtual Control CreateContentTemplateContainer() {
return new Control();
}
protected sealed override ControlCollection CreateControlCollection() {
// We override and seal this method because we have very special semantics
// on the behavior of this method and the type of ControlCollection we create.
return new SingleChildControlCollection(this);
}
protected internal virtual void Initialize() {
if (_triggers != null) {
if (ScriptManager.SupportsPartialRendering) {
// Triggers need to be initialized in initial requests as well as all postbacks,
// however only if partial rendering is enabled.
_triggers.Initialize();
}
}
}
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
protected internal override void OnInit(EventArgs e) {
base.OnInit(e);
RegisterPanel();
// DevDiv 79989: Whether the template has been set or not we need to ensure
// the template container is created by Init to remain consistent with 1.0.
if (_contentTemplateContainer == null) {
_contentTemplateContainer = CreateContentTemplateContainer();
AddContentTemplateContainer();
}
}
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
protected internal override void OnLoad(EventArgs e) {
base.OnLoad(e);
if (!DesignMode) {
if (!ScriptManager.IsInAsyncPostBack) {
// In partial rendering mode, ScriptManager calls Initialize.
// In all other cases we have to initialize here.
// This will cause things like AsyncPostBackTrigger to
// register event handlers for control events, which in turn
// will lead controls to track property values in view state
// and appropriately detect changes on the subsequent postbacks.
Initialize();
}
}
}
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
protected internal override void OnPreRender(EventArgs e) {
base.OnPreRender(e);
if (!ChildrenAsTriggers && UpdateMode == UpdatePanelUpdateMode.Always) {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.UpdatePanel_ChildrenTriggersAndUpdateAlways, ID));
}
}
[SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers")]
protected internal override void OnUnload(EventArgs e) {
if (!DesignMode && _panelRegistered) {
ScriptManager.UnregisterUpdatePanel(this);
}
base.OnUnload(e);
}
private void RegisterPanel() {
// Safeguard against registering in design mode, and against registering twice
if (!DesignMode && !_panelRegistered) {
// Before we can register we need to make sure all our parent panel (if any) has
// registered already. This is critical since the ScriptManager assumes that
// the panels are registered in a specific order.
Control parent = Parent;
while (parent != null) {
UpdatePanel parentUpdatePanel = parent as UpdatePanel;
if (parentUpdatePanel != null) {
parentUpdatePanel.RegisterPanel();
break;
}
parent = parent.Parent;
}
// Now we can register ourselves
ScriptManager.RegisterUpdatePanel(this);
_panelRegistered = true;
}
}
protected internal override void Render(HtmlTextWriter writer) {
IPage.VerifyRenderingInServerForm(this);
base.Render(writer);
}
protected internal override void RenderChildren(HtmlTextWriter writer) {
if (_asyncPostBackMode) {
Debug.Assert(!DesignMode, "Shouldn't be in DesignMode");
// Render might sometimes be called twice instead of just once if we are forcing
// all controls to render to ensure EventValidation is valid.
if (_rendered) {
return;
}
HtmlTextWriter childWriter = new HtmlTextWriter(new StringWriter(CultureInfo.CurrentCulture));
base.RenderChildren(childWriter);
PageRequestManager.EncodeString(writer, UpdatePanelToken, ClientID, childWriter.InnerWriter.ToString());
}
else {
Debug.Assert(!_rendered);
writer.AddAttribute(HtmlTextWriterAttribute.Id, ClientID);
if (_attributes != null) {
_attributes.AddAttributes(writer);
}
if (RenderMode == UpdatePanelRenderMode.Block) {
writer.RenderBeginTag(HtmlTextWriterTag.Div);
}
else {
writer.RenderBeginTag(HtmlTextWriterTag.Span);
}
base.RenderChildren(writer);
writer.RenderEndTag();
}
_rendered = true;
}
internal void SetAsyncPostBackMode(bool asyncPostBackMode) {
if (_asyncPostBackModeInitialized) {
throw new InvalidOperationException(AtlasWeb.UpdatePanel_SetPartialRenderingModeCalledOnce);
}
_asyncPostBackMode = asyncPostBackMode;
_asyncPostBackModeInitialized = true;
}
public void Update() {
if (UpdateMode == UpdatePanelUpdateMode.Always) {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.UpdatePanel_UpdateConditional, ID));
}
if (_asyncPostBackModeInitialized) {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.UpdatePanel_UpdateTooLate, ID));
}
_explicitUpdate = true;
}
string IAttributeAccessor.GetAttribute(string key) {
return (_attributes != null) ? _attributes[key] : null;
}
void IAttributeAccessor.SetAttribute(string key, string value) {
Attributes[key] = value;
}
private sealed class SingleChildControlCollection : ControlCollection {
private bool _allowClear;
public SingleChildControlCollection(Control owner)
: base(owner) {
}
internal void AddSingleChild(Control child) {
Debug.Assert(Count == 0, "The collection must be empty if this is called");
base.Add(child);
}
public override void Add(Control child) {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.UpdatePanel_CannotModifyControlCollection, Owner.ID));
}
public override void AddAt(int index, Control child) {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.UpdatePanel_CannotModifyControlCollection, Owner.ID));
}
public override void Clear() {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.UpdatePanel_CannotModifyControlCollection, Owner.ID));
}
internal void ClearInternal() {
try {
_allowClear = true;
base.Clear();
}
finally {
_allowClear = false;
}
}
public override void Remove(Control value) {
if (!_allowClear) {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.UpdatePanel_CannotModifyControlCollection, Owner.ID));
}
base.Remove(value);
}
public override void RemoveAt(int index) {
if (!_allowClear) {
throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, AtlasWeb.UpdatePanel_CannotModifyControlCollection, Owner.ID));
}
base.RemoveAt(index);
}
}
}
}
|