WebPartManager.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / xsp / System / Web / UI / WebParts / WebPartManager.cs / 4 / WebPartManager.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

namespace System.Web.UI.WebControls.WebParts { 
 
    using System;
    using System.Collections; 
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Configuration;
    using System.Drawing; 
    using System.Globalization;
    using System.IO; 
    using System.Reflection; 
    using System.Runtime.Serialization;
    using System.Runtime.Serialization.Formatters.Binary; 
    using System.Security;
    using System.Security.Cryptography;
    using System.Security.Permissions;
    using System.Text; 
    using System.Web;
    using System.Web.Compilation; 
    using System.Web.Configuration; 
    using System.Web.UI;
    using System.Web.UI.WebControls; 
    using System.Web.Util;
    using System.Xml;

    [ 
    Bindable(false),
    Designer("System.Web.UI.Design.WebControls.WebParts.WebPartManagerDesigner, " + AssemblyRef.SystemDesign), 
    NonVisualControl(), 
    ParseChildren(true),
    PersistChildren(false), 
    ViewStateModeById(),
    ]
    [AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
    [AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)] 
    public class WebPartManager : Control, INamingContainer, IPersonalizable {
 
        public static readonly WebPartDisplayMode CatalogDisplayMode = new CatalogWebPartDisplayMode(); 
        public static readonly WebPartDisplayMode ConnectDisplayMode = new ConnectWebPartDisplayMode();
        public static readonly WebPartDisplayMode DesignDisplayMode = new DesignWebPartDisplayMode(); 
        public static readonly WebPartDisplayMode EditDisplayMode = new EditWebPartDisplayMode();
        public static readonly WebPartDisplayMode BrowseDisplayMode = new BrowseWebPartDisplayMode();

        // Cache collections of ConnectionPoints for each object Type.  We store an array of 
        // 2 ConnectionPointCollections (consumer, provider) for each Type.  The Hashtable
        // is synchronized so it is threadsafe with multiple writers. 
        private static Hashtable ConnectionPointsCache; 

        private static readonly object AuthorizeWebPartEvent = new object(); 
        private static readonly object ConnectionsActivatedEvent = new object();
        private static readonly object ConnectionsActivatingEvent = new object();
        private static readonly object DisplayModeChangedEvent = new object();
        private static readonly object DisplayModeChangingEvent = new object(); 
        private static readonly object SelectedWebPartChangingEvent = new object();
        private static readonly object SelectedWebPartChangedEvent = new object(); 
        private static readonly object WebPartAddedEvent = new object(); 
        private static readonly object WebPartAddingEvent = new object();
        private static readonly object WebPartClosedEvent = new object(); 
        private static readonly object WebPartClosingEvent = new object();
        private static readonly object WebPartDeletedEvent = new object();
        private static readonly object WebPartDeletingEvent = new object();
        private static readonly object WebPartMovedEvent = new object(); 
        private static readonly object WebPartMovingEvent = new object();
        private static readonly object WebPartsConnectedEvent = new object(); 
        private static readonly object WebPartsConnectingEvent = new object(); 
        private static readonly object WebPartsDisconnectedEvent = new object();
        private static readonly object WebPartsDisconnectingEvent = new object(); 

        private PermissionSet _minimalPermissionSet;
        private PermissionSet _mediumPermissionSet;
 
        private const string DynamicConnectionIDPrefix = "c";
        private const string DynamicWebPartIDPrefix = "wp"; 
 
        private const int baseIndex = 0;
        private const int selectedWebPartIndex = 1; 
        private const int displayModeIndex = 2;
        private const int controlStateArrayLength = 3;

        private WebPartPersonalization _personalization; 
        private WebPartDisplayMode _displayMode;
        private WebPartDisplayModeCollection _displayModes; 
        private WebPartDisplayModeCollection _supportedDisplayModes; 
        private WebPartManagerInternals _internals;
 
        private bool _allowCreateDisplayTitles;
        private bool _pageInitComplete;

        // When this flag is set to false, then cancelled events are ignored.  We will not actually 
        // cancel the action even though e.Cancel is true.  (VSWhidbey 516012)
        private bool _allowEventCancellation; 
 
        private PersonalizationDictionary _personalizationState;
        private bool _hasDataChanged; 

        private WebPartConnectionCollection _staticConnections;
        private WebPartConnectionCollection _dynamicConnections;
 
        private WebPartZoneCollection _webPartZones;
        private TransformerTypeCollection _availableTransformers; 
 
        // Dictionary mapping a WebPart to its DisplayTitle.  Created and filled on demand when
        // GetDisplayTitle() is called after PreRender. 
        private IDictionary _displayTitles;

        // NOTE: We are no longer rendering the LRO or PDF characters (VSWhidbey 364897)
        // LRO is the Unicode left-to-right override marker.  Effectively creates a "run break" 
        // so that contents in parentheses et. al. maintain correct reading order regardless
        // of text direction (LTR or RTL).  PDF "pops" the formatting and allows ensuing text 
        // to lay out as it would w/o the markers.  The PDF is needed when constructing dialogs 
        // that use the web part titles.  We must use the Unicode characters instead of
        // , since the DisplayTitle is HTML Encoded before being rendered. 
        // (VSWhidbey 190501)
        // private static string LRO = new String((char)0x202d, 1);  // left-to-right override
        // private static string PDF = new String((char)0x202c, 1);  // pop directional formatting
 
        // PERF: At compile-time, compute strings to append to DisplayTitle
        // We chose to compute suffixes up to 20, since it is unlikely there will be more than 
        // 20 WebParts with the same title. 
        // The 0 element is currently not used, but is a placeholder so the index into the array
        // matches the string. 
        private static string[] displayTitleSuffix = new string[] {
            " [0]", " [1]", " [2]", " [3]", " [4]", " [5]", " [6]", " [7]", " [8]", " [9]", " [10]",
            " [11]", " [12]", " [13]", " [14]", " [15]", " [16]", " [17]", " [18]", " [19]", " [20]" };
 
        // Dictionary mapping a zone to the parts in the zone.  Used by GetAllWebPartsForZone
        // to improve performance. 
        private IDictionary _partsForZone; 

        // Contains the IDs of WebParts and Child Controls already added.  WebParts and the child 
        // controls of GenericWebParts share the same namespace, meaning you cannot have a WebPart
        // and a Child Control with the same ID. An exception is thrown if a WebPart or Child Control
        // is added with a duplicate ID.
        private IDictionary _partAndChildControlIDs; 

        // Contains the IDs of Zones already added.  An exception is thrown if a Zone is added with 
        // a duplicate ID. 
        private IDictionary _zoneIDs;
 
        private WebPart _selectedWebPart;

        private bool _renderClientScript;
 
        private const string DragOverlayElementHtmlTemplate = @"
"; private const string ExportSensitiveDataWarningDeclaration = "ExportSensitiveDataWarningDeclaration"; private const string CloseProviderWarningDeclaration = "CloseProviderWarningDeclaration"; private const string DeleteWarningDeclaration = "DeleteWarningDeclaration"; private const string StartupScript = @" "; private const string ZoneScript = @" zoneElement = document.getElementById('{0}'); if (zoneElement != null) {{ zoneObject = __wpm.AddZone(zoneElement, '{1}', {2}, {3}, '{4}');"; private const string ZonePartScript = @" zoneObject.AddWebPart(document.getElementById('{0}'), {1}, {2});"; private const string ZoneEndScript = @" }"; private const string AuthorizationFilterName = "AuthorizationFilter"; private const string ImportErrorMessageName = "ImportErrorMessage"; private const string ZoneIDName = "ZoneID"; private const string ZoneIndexName = "ZoneIndex"; internal const string ExportRootElement = "webParts"; internal const string ExportPartElement = "webPart"; internal const string ExportPartNamespaceAttribute = "xmlns"; internal const string ExportPartNamespaceValue = "http://schemas.microsoft.com/WebPart/v3"; internal const string ExportMetaDataElement = "metaData"; internal const string ExportTypeElement = "type"; internal const string ExportErrorMessageElement = "importErrorMessage"; internal const string ExportDataElement = "data"; internal const string ExportPropertiesElement = "properties"; internal const string ExportPropertyElement = "property"; internal const string ExportTypeNameAttribute = "name"; internal const string ExportUserControlSrcAttribute = "src"; internal const string ExportPropertyNameAttribute = "name"; internal const string ExportGenericPartPropertiesElement = "genericWebPartProperties"; internal const string ExportIPersonalizableElement = "ipersonalizable"; internal const string ExportPropertyTypeAttribute = "type"; internal const string ExportPropertyScopeAttribute = "scope"; internal const string ExportPropertyNullAttribute = "null"; private const string ExportTypeBool = "bool"; private const string ExportTypeInt = "int"; private const string ExportTypeChromeState = "chromestate"; private const string ExportTypeChromeType = "chrometype"; private const string ExportTypeColor = "color"; private const string ExportTypeDateTime = "datetime"; private const string ExportTypeDirection = "direction"; private const string ExportTypeDouble = "double"; private const string ExportTypeExportMode = "exportmode"; private const string ExportTypeFontSize = "fontsize"; private const string ExportTypeHelpMode = "helpmode"; private const string ExportTypeObject = "object"; private const string ExportTypeSingle = "single"; private const string ExportTypeString = "string"; private const string ExportTypeUnit = "unit"; /// /// public WebPartManager() { _allowEventCancellation = true; _displayMode = BrowseDisplayMode; _webPartZones = new WebPartZoneCollection(); _partAndChildControlIDs = new HybridDictionary(true /* caseInsensitive */); _zoneIDs = new HybridDictionary(true /* caseInsensitive */); } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public TransformerTypeCollection AvailableTransformers { get { if (_availableTransformers == null) { _availableTransformers = CreateAvailableTransformers(); } return _availableTransformers; } } [ WebCategory("Behavior"), WebSysDefaultValue(SR.WebPartManager_DefaultCloseProviderWarning), WebSysDescription(SR.WebPartManager_CloseProviderWarning) ] public virtual string CloseProviderWarning { get { object o = ViewState["CloseProviderWarning"]; return (o != null) ? (string)o : SR.GetString(SR.WebPartManager_DefaultCloseProviderWarning); } set { ViewState["CloseProviderWarning"] = value; } } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public WebPartConnectionCollection Connections { get { WebPartConnectionCollection connections = new WebPartConnectionCollection(this); if (_staticConnections != null) { foreach (WebPartConnection connection in _staticConnections) { if (!Internals.ConnectionDeleted(connection)) { connections.Add(connection); } } } if (_dynamicConnections != null) { foreach (WebPartConnection connection in _dynamicConnections) { if (!Internals.ConnectionDeleted(connection)) { connections.Add(connection); } } } connections.SetReadOnly(SR.WebPartManager_ConnectionsReadOnly); return connections; } } // Hide the Controls property from IntelliSense. The developer should use the // WebParts property instead. [ EditorBrowsable(EditorBrowsableState.Never), ] public override ControlCollection Controls { get { return base.Controls; } } [ WebCategory("Behavior"), WebSysDefaultValue(SR.WebPartManager_DefaultDeleteWarning), WebSysDescription(SR.WebPartManager_DeleteWarning) ] public virtual string DeleteWarning { get { object o = ViewState["DeleteWarning"]; return (o != null) ? (string)o : SR.GetString(SR.WebPartManager_DefaultDeleteWarning); } set { ViewState["DeleteWarning"] = value; } } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public virtual WebPartDisplayMode DisplayMode { get { return _displayMode; } set { if (value == null) { throw new ArgumentNullException("value"); } if (DisplayMode == value) { return; } if (SupportedDisplayModes.Contains(value) == false) { throw new ArgumentException(SR.GetString(SR.WebPartManager_InvalidDisplayMode), "value"); } if (!value.IsEnabled(this)) { throw new ArgumentException(SR.GetString(SR.WebPartManager_DisabledDisplayMode), "value"); } WebPartDisplayModeCancelEventArgs dmce = new WebPartDisplayModeCancelEventArgs(value); OnDisplayModeChanging(dmce); if (_allowEventCancellation && dmce.Cancel) { return; } // Custom display modes can take actions like this in the OnDisplayModeChanging method. // For example: // public override void OnDisplayModeChanging(WebPartDisplayModeCancelEventArgs e) { // base.OnDisplayModeChanging(e); // if (e.Cancel) return; // if (DisplayMode == CustomDisplayMode) { // // Take some actions and set e.Cancel=true if appropriate // } // } // End web part connecting if necessary if ((DisplayMode == ConnectDisplayMode) && (SelectedWebPart != null)) { EndWebPartConnecting(); if (SelectedWebPart != null) { // WebPartConnectModeChanging event was cancelled return; } } // End web part editing if necessary if ((DisplayMode == EditDisplayMode) && (SelectedWebPart != null)) { EndWebPartEditing(); if (SelectedWebPart != null) { // WebPartEditModeChanging event was cancelled return; } } WebPartDisplayModeEventArgs dme = new WebPartDisplayModeEventArgs(DisplayMode); _displayMode = value; OnDisplayModeChanged(dme); } } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public WebPartDisplayModeCollection DisplayModes { get { if (_displayModes == null) { _displayModes = CreateDisplayModes(); _displayModes.SetReadOnly(SR.WebPartManager_DisplayModesReadOnly); } return _displayModes; } } protected internal WebPartConnectionCollection DynamicConnections { get { if (_dynamicConnections == null) { _dynamicConnections = new WebPartConnectionCollection(this); } return _dynamicConnections; } } [ DefaultValue(true), WebCategory("Behavior"), WebSysDescription(SR.WebPartManager_EnableClientScript) ] public virtual bool EnableClientScript { get { object o = ViewState["EnableClientScript"]; return (o != null) ? (bool)o : true; } set { ViewState["EnableClientScript"] = value; } } // Theming must be enabled, so the WebPart child controls have theming enabled [ Browsable(false), DefaultValue(true), EditorBrowsable(EditorBrowsableState.Never), ] public override bool EnableTheming { get { return true; } set { throw new NotSupportedException(SR.GetString(SR.WebPartManager_CantSetEnableTheming)); } } [ WebCategory("Behavior"), WebSysDefaultValue(SR.WebPartChrome_ConfirmExportSensitive), WebSysDescription(SR.WebPartManager_ExportSensitiveDataWarning) ] public virtual string ExportSensitiveDataWarning { get { object o = ViewState["ExportSensitiveDataWarning"]; return (o != null) ? (string)o : SR.GetString(SR.WebPartChrome_ConfirmExportSensitive); } set { ViewState["ExportSensitiveDataWarning"] = value; } } [ EditorBrowsable(EditorBrowsableState.Never), ] protected WebPartManagerInternals Internals { get { if (_internals == null) { _internals = new WebPartManagerInternals(this); } return _internals; } } /// /// protected virtual bool IsCustomPersonalizationStateDirty { get { return _hasDataChanged; } } // PermissionSet that allows only Execution and AspNetHostingPermissionLevel.Medium. // AspNetHostingPermissionLevel.Medium is needed to call BuildManager.GetType(). // Used for during Import for type deserialization. private PermissionSet MediumPermissionSet { get { if (_mediumPermissionSet == null) { _mediumPermissionSet = new PermissionSet(PermissionState.None); _mediumPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution)); _mediumPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Medium)); } return _mediumPermissionSet; } } // PermissionSet that allows only Execution and AspNetHostingPermissionLevel.Minimal. // Used for during Import for everything except type deserialization. private PermissionSet MinimalPermissionSet { get { if (_minimalPermissionSet == null) { _minimalPermissionSet = new PermissionSet(PermissionState.None); _minimalPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution)); _minimalPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Minimal)); } return _minimalPermissionSet; } } /// /// [ DefaultValue(null), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), NotifyParentProperty(true), PersistenceMode(PersistenceMode.InnerProperty), WebCategory("Behavior"), WebSysDescription(SR.WebPartManager_Personalization) ] public WebPartPersonalization Personalization { get { if (_personalization == null) { _personalization = CreatePersonalization(); } return _personalization; } } internal bool RenderClientScript { get { return _renderClientScript; } } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public WebPart SelectedWebPart { get { return _selectedWebPart; } } [ Browsable(false), DefaultValue(""), EditorBrowsable(EditorBrowsableState.Never), ] public override string SkinID { get { return String.Empty; } set { throw new NotSupportedException(SR.GetString(SR.NoThemingSupport, this.GetType().Name)); } } [ DefaultValue(null), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), MergableProperty(false), PersistenceMode(PersistenceMode.InnerProperty), WebCategory("Behavior"), WebSysDescription(SR.WebPartManager_StaticConnections), ] public WebPartConnectionCollection StaticConnections { get { if (_staticConnections == null) { _staticConnections = new WebPartConnectionCollection(this); } return _staticConnections; } } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public WebPartDisplayModeCollection SupportedDisplayModes { get { if (_supportedDisplayModes == null) { _supportedDisplayModes = new WebPartDisplayModeCollection(); foreach (WebPartDisplayMode mode in DisplayModes) { if (mode.AssociatedWithToolZone == false) { _supportedDisplayModes.Add(mode); } } _supportedDisplayModes.SetReadOnly(SR.WebPartManager_DisplayModesReadOnly); } return _supportedDisplayModes; } } [ Bindable(false), Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsable(EditorBrowsableState.Never), ] public override bool Visible { get { // Even though we are a non-visual control, this returns true, because we want our // child controls (the WebParts) to be Visible. return true; } set { throw new NotSupportedException(SR.GetString(SR.ControlNonVisual, this.GetType().Name)); } } /// /// All the WebParts on the page. /// [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public WebPartCollection WebParts { get { // PERF: Consider changing WebPartCollection so it just wraps the ControlCollection, // instead of copying the controls to a new collection. if (HasControls()) { return new WebPartCollection(Controls); } else { return new WebPartCollection(); } } } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) ] public WebPartZoneCollection Zones { get { return _webPartZones; } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_AuthorizeWebPart) ] public event WebPartAuthorizationEventHandler AuthorizeWebPart { add { Events.AddHandler(AuthorizeWebPartEvent, value); } remove { Events.RemoveHandler(AuthorizeWebPartEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_ConnectionsActivated) ] public event EventHandler ConnectionsActivated { add { Events.AddHandler(ConnectionsActivatedEvent, value); } remove { Events.RemoveHandler(ConnectionsActivatedEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_ConnectionsActivating) ] public event EventHandler ConnectionsActivating { add { Events.AddHandler(ConnectionsActivatingEvent, value); } remove { Events.RemoveHandler(ConnectionsActivatingEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_DisplayModeChanged) ] public event WebPartDisplayModeEventHandler DisplayModeChanged { add { Events.AddHandler(DisplayModeChangedEvent, value); } remove { Events.RemoveHandler(DisplayModeChangedEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_DisplayModeChanging) ] public event WebPartDisplayModeCancelEventHandler DisplayModeChanging { add { Events.AddHandler(DisplayModeChangingEvent, value); } remove { Events.RemoveHandler(DisplayModeChangingEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_SelectedWebPartChanged) ] public event WebPartEventHandler SelectedWebPartChanged { add { Events.AddHandler(SelectedWebPartChangedEvent, value); } remove { Events.RemoveHandler(SelectedWebPartChangedEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_SelectedWebPartChanging) ] public event WebPartCancelEventHandler SelectedWebPartChanging { add { Events.AddHandler(SelectedWebPartChangingEvent, value); } remove { Events.RemoveHandler(SelectedWebPartChangingEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_WebPartAdded) ] public event WebPartEventHandler WebPartAdded { add { Events.AddHandler(WebPartAddedEvent, value); } remove { Events.RemoveHandler(WebPartAddedEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_WebPartAdding) ] public event WebPartAddingEventHandler WebPartAdding { add { Events.AddHandler(WebPartAddingEvent, value); } remove { Events.RemoveHandler(WebPartAddingEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_WebPartClosed) ] public event WebPartEventHandler WebPartClosed { add { Events.AddHandler(WebPartClosedEvent, value); } remove { Events.RemoveHandler(WebPartClosedEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_WebPartClosing) ] public event WebPartCancelEventHandler WebPartClosing { add { Events.AddHandler(WebPartClosingEvent, value); } remove { Events.RemoveHandler(WebPartClosingEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_WebPartDeleted) ] public event WebPartEventHandler WebPartDeleted { add { Events.AddHandler(WebPartDeletedEvent, value); } remove { Events.RemoveHandler(WebPartDeletedEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_WebPartDeleting) ] public event WebPartCancelEventHandler WebPartDeleting { add { Events.AddHandler(WebPartDeletingEvent, value); } remove { Events.RemoveHandler(WebPartDeletingEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_WebPartMoved) ] public event WebPartEventHandler WebPartMoved { add { Events.AddHandler(WebPartMovedEvent, value); } remove { Events.RemoveHandler(WebPartMovedEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_WebPartMoving) ] public event WebPartMovingEventHandler WebPartMoving { add { Events.AddHandler(WebPartMovingEvent, value); } remove { Events.RemoveHandler(WebPartMovingEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_WebPartsConnected) ] public event WebPartConnectionsEventHandler WebPartsConnected { add { Events.AddHandler(WebPartsConnectedEvent, value); } remove { Events.RemoveHandler(WebPartsConnectedEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_WebPartsConnecting) ] public event WebPartConnectionsCancelEventHandler WebPartsConnecting { add { Events.AddHandler(WebPartsConnectingEvent, value); } remove { Events.RemoveHandler(WebPartsConnectingEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_WebPartsDisconnected) ] public event WebPartConnectionsEventHandler WebPartsDisconnected { add { Events.AddHandler(WebPartsDisconnectedEvent, value); } remove { Events.RemoveHandler(WebPartsDisconnectedEvent, value); } } [ WebCategory("Action"), WebSysDescription(SR.WebPartManager_WebPartsDisconnecting) ] public event WebPartConnectionsCancelEventHandler WebPartsDisconnecting { add { Events.AddHandler(WebPartsDisconnectingEvent, value); } remove { Events.RemoveHandler(WebPartsDisconnectingEvent, value); } } protected virtual void ActivateConnections() { try { // ActivateConnections() is called as a result of no user action, so the events // should not be cancellable. (VSWhidbey 516012) _allowEventCancellation = false; foreach (WebPartConnection connection in ConnectionsToActivate()) { connection.Activate(); } } finally { _allowEventCancellation = true; } } // Called by WebPartManagerInternals internal void AddWebPart(WebPart webPart) { ((WebPartManagerControlCollection)Controls).AddWebPart(webPart); } private WebPart AddDynamicWebPartToZone(WebPart webPart, WebPartZoneBase zone, int zoneIndex) { Debug.Assert(Personalization.IsModifiable); // Zone should not be set on a dynamic web part being added to the page for the first time Debug.Assert(webPart.Zone == null); // Only add WebPart if IsAuthorized(webPart) == true if (!IsAuthorized(webPart)) { return null; } WebPart newWebPart = CopyWebPart(webPart); Internals.SetIsStatic(newWebPart, false); Internals.SetIsShared(newWebPart, Personalization.Scope == PersonalizationScope.Shared); AddWebPartToZone(newWebPart, zone, zoneIndex); Internals.AddWebPart(newWebPart); // We set the personalized properties on the added WebPart AFTER it has been added to the // control tree, since we want to exactly recreate the process the WebPart will go through // when it is added from Personalization. Personalization.CopyPersonalizationState(webPart, newWebPart); // Raise event at very end of Add method OnWebPartAdded(new WebPartEventArgs(newWebPart)); return newWebPart; } // Returns the WebPart that was actually added. For an existing Closed WebPart, this is a reference // to the webPart parameter. For a new DynamicWebPart, this will be a copy of the webPart parameter. public WebPart AddWebPart(WebPart webPart, WebPartZoneBase zone, int zoneIndex) { Personalization.EnsureEnabled(/* ensureModifiable */ true); if (webPart == null) { throw new ArgumentNullException("webPart"); } // Do not check that Controls.Contains(webPart), since this will be called on a WebPart // before it is added to the Controls collection. if (zone == null) { throw new ArgumentNullException("zone"); } if (_webPartZones.Contains(zone) == false) { throw new ArgumentException(SR.GetString(SR.WebPartManager_MustRegister), "zone"); } if (zoneIndex < 0) { throw new ArgumentOutOfRangeException("zoneIndex"); } if (webPart.Zone != null && !webPart.IsClosed) { throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyInZone), "webPart"); } WebPartAddingEventArgs e = new WebPartAddingEventArgs(webPart, zone, zoneIndex); OnWebPartAdding(e); if (_allowEventCancellation && e.Cancel) { return null; } WebPart addedWebPart; // If a part is already in the controls collection, dynamic or static, just make it // not closed and add it to the specified zone if (Controls.Contains(webPart)) { addedWebPart = webPart; AddWebPartToZone(webPart, zone, zoneIndex); OnWebPartAdded(new WebPartEventArgs(addedWebPart)); } else { addedWebPart = AddDynamicWebPartToZone(webPart, zone, zoneIndex); // OnWebPartAdded() is called by AddDynamicWebPartToZone } #if DEBUG CheckPartZoneIndexes(zone); #endif return addedWebPart; } /// /// Adds the part to the dictionary mapping zones to parts. /// private void AddWebPartToDictionary(WebPart webPart) { if (_partsForZone != null) { string zoneID = Internals.GetZoneID(webPart); if (!String.IsNullOrEmpty(zoneID)) { SortedList partsForZone = (SortedList)(_partsForZone[zoneID]); if (partsForZone == null) { partsForZone = new SortedList(new WebPart.ZoneIndexComparer()); _partsForZone[zoneID] = partsForZone; } partsForZone.Add(webPart, null); } } } /// /// Adds a web part to a zone at the specified zoneIndex, and renumbers all the parts in the zone /// sequentially. /// private void AddWebPartToZone(WebPart webPart, WebPartZoneBase zone, int zoneIndex) { Debug.Assert(webPart.Zone == null || webPart.IsClosed); // All the parts for the zone IList allParts = GetAllWebPartsForZone(zone); // The parts for the zone that were actually rendered WebPartCollection renderedParts = GetWebPartsForZone(zone); // The zoneIndex parameter is the desired index in the renderedParts collection. // Calculate the destination index into the allParts collection. (VSWhidbey 77719) int allPartsDestinationIndex; if (zoneIndex < renderedParts.Count) { WebPart successor = renderedParts[zoneIndex]; Debug.Assert(allParts.Contains(successor)); allPartsDestinationIndex = allParts.IndexOf(successor); } else { allPartsDestinationIndex = allParts.Count; } // Renumber all parts in the zone, leaving room for the added part for (int i = 0; i < allPartsDestinationIndex; i++) { WebPart part = ((WebPart)allParts[i]); Internals.SetZoneIndex(part, i); } for (int i = allPartsDestinationIndex; i < allParts.Count; i++) { WebPart part = ((WebPart)allParts[i]); Internals.SetZoneIndex(part, i + 1); } // Set the part index and add to destination zone Internals.SetZoneIndex(webPart, allPartsDestinationIndex); Internals.SetZoneID(webPart, zone.ID); Internals.SetIsClosed(webPart, false); _hasDataChanged = true; AddWebPartToDictionary(webPart); } public virtual void BeginWebPartConnecting(WebPart webPart) { Personalization.EnsureEnabled(/* ensureModifiable */ true); if (webPart == null) { throw new ArgumentNullException("webPart"); } if (webPart.IsClosed) { throw new ArgumentException(SR.GetString(SR.WebPartManager_CantBeginConnectingClosed), "webPart"); } if (!Controls.Contains(webPart)) { throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart"); } if (DisplayMode != ConnectDisplayMode) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_MustBeInConnect)); } if (webPart == SelectedWebPart) { throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyInConnect), "webPart"); } WebPartCancelEventArgs ce = new WebPartCancelEventArgs(webPart); OnSelectedWebPartChanging(ce); if (_allowEventCancellation && ce.Cancel) { return; } if (SelectedWebPart != null) { EndWebPartConnecting(); if (SelectedWebPart != null) { // The ConnectModeChange was cancelled return; } } SetSelectedWebPart(webPart); Internals.CallOnConnectModeChanged(webPart); OnSelectedWebPartChanged(new WebPartEventArgs(webPart)); } public virtual void BeginWebPartEditing(WebPart webPart) { Personalization.EnsureEnabled(/* ensureModifiable */ true); if (webPart == null) { throw new ArgumentNullException("webPart"); } if (webPart.IsClosed) { throw new ArgumentException(SR.GetString(SR.WebPartManager_CantBeginEditingClosed), "webPart"); } if (!Controls.Contains(webPart)) { throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart"); } if (DisplayMode != EditDisplayMode) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_MustBeInEdit)); } if (webPart == SelectedWebPart) { throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyInEdit), "webPart"); } WebPartCancelEventArgs ce = new WebPartCancelEventArgs(webPart); OnSelectedWebPartChanging(ce); if (_allowEventCancellation && ce.Cancel) { return; } if (SelectedWebPart != null) { EndWebPartEditing(); if (SelectedWebPart != null) { // The EditModeChange was cancelled return; } } SetSelectedWebPart(webPart); Internals.CallOnEditModeChanged(webPart); OnSelectedWebPartChanged(new WebPartEventArgs(webPart)); } #if DEBUG /// /// Checks that the web parts in a zone are numbered sequentially. This invariant /// should hold at the exit of AddWebPart, CloseWebPart, DeleteWebPart, MoveWebPart, and RegisterZone. /// private void CheckPartZoneIndexes(WebPartZoneBase zone) { ICollection parts = GetAllWebPartsForZone(zone); int index = 0; foreach (WebPart part in parts) { if (part.ZoneIndex != index) { System.Text.StringBuilder builder = new System.Text.StringBuilder(); builder.Append("Title\tZone\tZoneIndex"); foreach (WebPart part2 in Controls) { string zoneTitle = (part2.Zone == null) ? "null" : part2.Zone.DisplayTitle; builder.Append(part2.DisplayTitle + "\t" + zoneTitle + "\t" + part2.ZoneIndex); } Debug.Assert(false, builder.ToString()); return; } index++; } } #endif // DEBUG protected virtual bool CheckRenderClientScript() { bool renderClientScript = false; if (EnableClientScript && Page != null) { HttpBrowserCapabilities browserCaps = Page.Request.Browser; // Win32 IE5.5+ and JScript 5.5+ if (browserCaps.Win32 && (browserCaps.MSDomVersion.CompareTo(new Version(5, 5)) >= 0)) { renderClientScript = true; } } return renderClientScript; } // When a Zone is deleted, any web parts in that zone should move to the page catalog. // VSWhidbey 77708 private void CloseOrphanedParts() { // PERF: Use Controls instead of WebParts property, to avoid creating another collection if (HasControls()) { try { // CloseOrphanedParts() is called as a result of no user action, so the events // should not be cancellable. (VSWhidbey 516012) _allowEventCancellation = false; foreach (WebPart part in Controls) { if (part.IsOrphaned) { CloseWebPart(part); } } } finally { _allowEventCancellation = true; } } } public bool CanConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint, WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint) { return CanConnectWebParts(provider, providerConnectionPoint, consumer, consumerConnectionPoint, null); } public virtual bool CanConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint, WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint, WebPartTransformer transformer) { return CanConnectWebPartsCore(provider, providerConnectionPoint, consumer, consumerConnectionPoint, transformer, false); } private bool CanConnectWebPartsCore(WebPart provider, ProviderConnectionPoint providerConnectionPoint, WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint, WebPartTransformer transformer, bool throwOnError) { if (!Personalization.IsModifiable) { if (throwOnError) { // Will throw appropriate exception Personalization.EnsureEnabled(/* ensureModifiable */ true); } else { return false; } } if (provider == null) { throw new ArgumentNullException("provider"); } if (!Controls.Contains(provider)) { throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "provider"); } if (consumer == null) { throw new ArgumentNullException("consumer"); } if (!Controls.Contains(consumer)) { throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "consumer"); } if (providerConnectionPoint == null) { throw new ArgumentNullException("providerConnectionPoint"); } if (consumerConnectionPoint == null) { throw new ArgumentNullException("consumerConnectionPoint"); } Control providerControl = provider.ToControl(); Control consumerControl = consumer.ToControl(); if (providerConnectionPoint.ControlType != providerControl.GetType()) { throw new ArgumentException(SR.GetString(SR.WebPartManager_InvalidConnectionPoint), "providerConnectionPoint"); } if (consumerConnectionPoint.ControlType != consumerControl.GetType()) { throw new ArgumentException(SR.GetString(SR.WebPartManager_InvalidConnectionPoint), "consumerConnectionPoint"); } if (provider == consumer) { if (throwOnError) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectToSelf)); } else { return false; } } if (provider.IsClosed) { if (throwOnError) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectClosed, provider.ID)); } else { return false; } } if (consumer.IsClosed) { if (throwOnError) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectClosed, consumer.ID)); } else { return false; } } if (!providerConnectionPoint.GetEnabled(providerControl)) { if (throwOnError) { throw new InvalidOperationException(SR.GetString( SR.WebPartConnection_DisabledConnectionPoint, providerConnectionPoint.ID, provider.ID)); } else { return false; } } if (!consumerConnectionPoint.GetEnabled(consumerControl)) { if (throwOnError) { throw new InvalidOperationException(SR.GetString( SR.WebPartConnection_DisabledConnectionPoint, consumerConnectionPoint.ID, consumer.ID)); } else { return false; } } // Check AllowsMultipleConnections on each ConnectionPoint if (!providerConnectionPoint.AllowsMultipleConnections) { foreach (WebPartConnection c in Connections) { if (c.Provider == provider && c.ProviderConnectionPoint == providerConnectionPoint) { if (throwOnError) { throw new InvalidOperationException(SR.GetString( SR.WebPartConnection_Duplicate, providerConnectionPoint.ID, provider.ID)); } else { return false; } } } } if (!consumerConnectionPoint.AllowsMultipleConnections) { foreach (WebPartConnection c in Connections) { if (c.Consumer == consumer && c.ConsumerConnectionPoint == consumerConnectionPoint) { if (throwOnError) { throw new InvalidOperationException(SR.GetString( SR.WebPartConnection_Duplicate, consumerConnectionPoint.ID, consumer.ID)); } else { return false; } } } } if (transformer == null) { if (providerConnectionPoint.InterfaceType != consumerConnectionPoint.InterfaceType) { if (throwOnError) { throw new InvalidOperationException(SR.GetString( SR.WebPartConnection_NoCommonInterface, new string[] {providerConnectionPoint.DisplayName, provider.ID, consumerConnectionPoint.DisplayName, consumer.ID})); } else { return false; } } ConnectionInterfaceCollection secondaryInterfaces = providerConnectionPoint.GetSecondaryInterfaces(providerControl); if (!consumerConnectionPoint.SupportsConnection(consumerControl, secondaryInterfaces)) { if (throwOnError) { throw new InvalidOperationException(SR.GetString( SR.WebPartConnection_IncompatibleSecondaryInterfaces, new string[] { consumerConnectionPoint.DisplayName, consumer.ID, providerConnectionPoint.DisplayName, provider.ID})); } else { return false; } } } else { Type transformerType = transformer.GetType(); if (!AvailableTransformers.Contains(transformerType)) { throw new InvalidOperationException(SR.GetString( SR.WebPartConnection_TransformerNotAvailable, transformerType.FullName)); } // Check matching interfaces on connection points and transformer attribute. // Note that we require the connection interfaces to match exactly. We do not match // a derived interface type. This is because we want to simplify the interface matching // algorithm when transformers are involved. If we allowed derived interfaces to match, // then we would to take into account the "closest" match if multiple transformers // have compatible interfaces. Type transformerConsumerType = WebPartTransformerAttribute.GetConsumerType(transformerType); Type transformerProviderType = WebPartTransformerAttribute.GetProviderType(transformerType); if (providerConnectionPoint.InterfaceType != transformerConsumerType) { if (throwOnError) { throw new InvalidOperationException(SR.GetString( SR.WebPartConnection_IncompatibleProviderTransformer, providerConnectionPoint.DisplayName, provider.ID, transformerType.FullName)); } else { return false; } } if (transformerProviderType != consumerConnectionPoint.InterfaceType) { if (throwOnError) { throw new InvalidOperationException(SR.GetString( SR.WebPartConnection_IncompatibleConsumerTransformer, transformerType.FullName, consumerConnectionPoint.DisplayName, consumer.ID)); } else { return false; } } // A transformer never provides any secondary interfaces if (!consumerConnectionPoint.SupportsConnection(consumerControl, ConnectionInterfaceCollection.Empty)) { if (throwOnError) { throw new InvalidOperationException(SR.GetString( SR.WebPartConnection_ConsumerRequiresSecondaryInterfaces, consumerConnectionPoint.DisplayName, consumer.ID)); } else { return false; } } } return true; } public void CloseWebPart(WebPart webPart) { CloseOrDeleteWebPart(webPart, /* delete */ false); } private void CloseOrDeleteWebPart(WebPart webPart, bool delete) { Personalization.EnsureEnabled(/* ensureModifiable */ true); if (webPart == null) { throw new ArgumentNullException("webPart"); } if (!Controls.Contains(webPart)) { throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart"); } if (!delete && webPart.IsClosed) { // Throw an exception instead of just returning. If the shared user and per user close // a WebPart at the same time, then the WebPartZoneBase should not call CloseWebPart // if the WebPart is now closed. throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyClosed), "webPart"); } if (delete) { if (webPart.IsStatic) { // Can't delete static parts throw new ArgumentException(SR.GetString(SR.WebPartManager_CantDeleteStatic), "webPart"); } else if (webPart.IsShared && (Personalization.Scope == PersonalizationScope.User)) { // Can't delete shared part in user scope throw new ArgumentException(SR.GetString(SR.WebPartManager_CantDeleteSharedInUserScope), "webPart"); } } WebPartCancelEventArgs ce = new WebPartCancelEventArgs(webPart); if (delete) { OnWebPartDeleting(ce); } else { OnWebPartClosing(ce); } if (_allowEventCancellation && ce.Cancel) { return; } if ((DisplayMode == ConnectDisplayMode) && (webPart == SelectedWebPart)) { EndWebPartConnecting(); if (SelectedWebPart != null) { // The ConnectModeChange was cancelled return; } } // VSWhidbey 77768 if ((DisplayMode == EditDisplayMode) && (webPart == SelectedWebPart)) { EndWebPartEditing(); if (SelectedWebPart != null) { // The EditModeChange was cancelled return; } } if (delete) { Internals.CallOnDeleting(webPart); } else { Internals.CallOnClosing(webPart); } #if DEBUG WebPartZoneBase zone = webPart.Zone; #endif // If we are deleting a closed WebPart, it has already been removed from // its Zone, so there is no need to do it again. if (!webPart.IsClosed) { RemoveWebPartFromZone(webPart); } DisconnectWebPart(webPart); if (delete) { Internals.RemoveWebPart(webPart); // Raise the WebPartDeleted event after changing the WebPart properties // The WebPartDeleting event is raised before changing the WebPart properties OnWebPartDeleted(new WebPartEventArgs(webPart)); } else { // Raise the WebPartClosed event after changing the WebPart properties // The WebPartClosing event is raised before changing the WebPart properties OnWebPartClosed(new WebPartEventArgs(webPart)); } #if DEBUG if (zone != null) { CheckPartZoneIndexes(zone); } #endif } private WebPartConnection[] ConnectionsToActivate() { // PERF: We could implement this with a sorted list to simplify the code ArrayList connectionsToActivate = new ArrayList(); // Contains the connection IDs we have already seen HybridDictionary connectionIDs = new HybridDictionary(true /* caseInsensitive */); WebPartConnection[] connections = new WebPartConnection[StaticConnections.Count + DynamicConnections.Count]; StaticConnections.CopyTo(connections, 0); DynamicConnections.CopyTo(connections, StaticConnections.Count); foreach (WebPartConnection connection in connections) { ConnectionsToActivateHelper(connection, connectionIDs, connectionsToActivate); } // Check unshared connections for conflicts with shared connections // Maybe this should only be done in user scope WebPartConnection[] connectionsToActivateArray = (WebPartConnection[])connectionsToActivate.ToArray(typeof(WebPartConnection)); foreach (WebPartConnection connection in connectionsToActivateArray) { if (connection.IsShared) { continue; } ArrayList connectionsToDelete = new ArrayList(); foreach (WebPartConnection otherConnection in connectionsToActivate) { if (connection == otherConnection) { continue; } if (otherConnection.IsShared && connection.ConflictsWith(otherConnection)) { // Delete shared connection. connectionsToDelete.Add(otherConnection); } } foreach (WebPartConnection connectionToDelete in connectionsToDelete) { DisconnectWebParts(connectionToDelete); connectionsToActivate.Remove(connectionToDelete); } } // Check shared, nonstatic connections for conflicts with static connections connectionsToActivateArray = (WebPartConnection[])connectionsToActivate.ToArray(typeof(WebPartConnection)); foreach (WebPartConnection connection in connectionsToActivateArray) { if (!connection.IsShared || connection.IsStatic) { continue; } ArrayList connectionsToDelete = new ArrayList(); foreach (WebPartConnection otherConnection in connectionsToActivate) { if (connection == otherConnection) { continue; } if (otherConnection.IsStatic && connection.ConflictsWith(otherConnection)) { // Delete static connection. connectionsToDelete.Add(otherConnection); } } foreach (WebPartConnection connectionToDelete in connectionsToDelete) { DisconnectWebParts(connectionToDelete); connectionsToActivate.Remove(connectionToDelete); } } // Check all remaining connections for conflicts. Any conflicts at this stage will // cause an error to be rendered in the consumer WebPart, and the conflicting connections // will not be activated. ArrayList finalConnectionsToActivate = new ArrayList(); foreach (WebPartConnection connection in connectionsToActivate) { bool hasConflict = false; foreach (WebPartConnection otherConnection in connectionsToActivate) { if (connection == otherConnection) { continue; } if (connection.ConflictsWithConsumer(otherConnection)) { connection.Consumer.SetConnectErrorMessage(SR.GetString( SR.WebPartConnection_Duplicate, connection.ConsumerConnectionPoint.DisplayName, connection.Consumer.DisplayTitle)); hasConflict = true; } if (connection.ConflictsWithProvider(otherConnection)) { connection.Consumer.SetConnectErrorMessage(SR.GetString( SR.WebPartConnection_Duplicate, connection.ProviderConnectionPoint.DisplayName, connection.Provider.DisplayTitle)); hasConflict = true; } } if (!hasConflict) { finalConnectionsToActivate.Add(connection); } } // Don't allow the user to modify the StaticConnections collection after its connections have // been activated. Use property instead of field to force creation of collection. StaticConnections.SetReadOnly(SR.WebPartManager_StaticConnectionsReadOnly); // The user can't directly change the DynamicConnections property since it is internal. // Make it read-only in case we have a bug and try to change it after activation. // We check the read-only status of this collection in ConnectWebParts() and DisconnectWebParts(). DynamicConnections.SetReadOnly(SR.WebPartManager_DynamicConnectionsReadOnly); return (WebPartConnection[])finalConnectionsToActivate.ToArray(typeof(WebPartConnection)); } // If we think we should activate the connection, adds it to the dictionary under the key // for its provider and consumer connection points. private void ConnectionsToActivateHelper(WebPartConnection connection, IDictionary connectionIDs, ArrayList connectionsToActivate) { string connectionID = connection.ID; if (String.IsNullOrEmpty(connectionID)) { throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_NoID)); } if (connectionIDs.Contains(connectionID)) { throw new InvalidOperationException( SR.GetString(SR.WebPartManager_DuplicateConnectionID, connectionID)); } connectionIDs.Add(connectionID, null); if (connection.Deleted) { return; } WebPart providerWebPart = connection.Provider; if (providerWebPart == null) { if (connection.IsStatic) { // throw an exception, to alert the developer that his static connection is invalid throw new InvalidOperationException(SR.GetString( SR.WebPartConnection_NoProvider, connection.ProviderID)); } else { // Silently delete the connection, since this is a valid runtime scenario. // A connected web part may have been deleted. DisconnectWebParts(connection); return; } } WebPart consumerWebPart = connection.Consumer; if (consumerWebPart == null) { if (connection.IsStatic) { // throw an exception, to alert the developer that his static connection is invalid throw new InvalidOperationException(SR.GetString( SR.WebPartConnection_NoConsumer, connection.ConsumerID)); } else { // Silently delete the connection, since this is a valid runtime scenario. // A connected web part may have been deleted. DisconnectWebParts(connection); return; } } // Do not activate connections involving ProxyWebParts if (providerWebPart is ProxyWebPart || consumerWebPart is ProxyWebPart) { return; } Control providerControl = providerWebPart.ToControl(); Control consumerControl = consumerWebPart.ToControl(); // Cannot connect a WebPart to itself if (providerControl == consumerControl) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectToSelf)); } ProviderConnectionPoint providerConnectionPoint = connection.ProviderConnectionPoint; if (providerConnectionPoint == null) { consumerWebPart.SetConnectErrorMessage(SR.GetString( SR.WebPartConnection_NoProviderConnectionPoint, connection.ProviderConnectionPointID, providerWebPart.DisplayTitle)); return; } // Don't need to check that providerConnectionPoint is enabled, since this will be checked // in WebPartConnection.Activate(). ConsumerConnectionPoint consumerConnectionPoint = connection.ConsumerConnectionPoint; if (consumerConnectionPoint == null) { consumerWebPart.SetConnectErrorMessage(SR.GetString( SR.WebPartConnection_NoConsumerConnectionPoint, connection.ConsumerConnectionPointID, consumerWebPart.DisplayTitle)); return; } // Don't need to check that consumer ConnectionPoint is enabled, since this will be checked // in WebPartConnection.Activate(). connectionsToActivate.Add(connection); } public WebPartConnection ConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint, WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint) { return ConnectWebParts(provider, providerConnectionPoint, consumer, consumerConnectionPoint, null); } public virtual WebPartConnection ConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint, WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint, WebPartTransformer transformer) { CanConnectWebPartsCore(provider, providerConnectionPoint, consumer, consumerConnectionPoint, transformer, /*throwOnError*/ true); if (DynamicConnections.IsReadOnly) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_ConnectTooLate)); } WebPartConnectionsCancelEventArgs ce = new WebPartConnectionsCancelEventArgs( provider, providerConnectionPoint, consumer, consumerConnectionPoint); OnWebPartsConnecting(ce); if (_allowEventCancellation && ce.Cancel) { return null; } Control providerControl = provider.ToControl(); Control consumerControl = consumer.ToControl(); WebPartConnection connection = new WebPartConnection(); connection.ID = CreateDynamicConnectionID(); connection.ProviderID = providerControl.ID; connection.ConsumerID = consumerControl.ID; connection.ProviderConnectionPointID = providerConnectionPoint.ID; connection.ConsumerConnectionPointID = consumerConnectionPoint.ID; if (transformer != null) { Internals.SetTransformer(connection, transformer); } Internals.SetIsShared(connection, Personalization.Scope == PersonalizationScope.Shared); Internals.SetIsStatic(connection, false); DynamicConnections.Add(connection); _hasDataChanged = true; OnWebPartsConnected(new WebPartConnectionsEventArgs(provider, providerConnectionPoint, consumer, consumerConnectionPoint, connection)); return connection; } // Returns a copy of the WebPart, with all the properties reset to their default value. // If the WebPart is a GenericWebPart, returns a copy of the GenericWebPart and a copy of the // ChildControl inside the GenericWebPart. The ID of the new WebPart and ChildControl should // be set to a value obtained from CreateDynamicWebPartID. // Virtual because a derived WebPartManager will deserialize a WebPart from XML in this method. protected virtual WebPart CopyWebPart(WebPart webPart) { WebPart newWebPart; GenericWebPart genericWebPart = webPart as GenericWebPart; if (genericWebPart != null) { Control childControl = genericWebPart.ChildControl; VerifyType(childControl); Type childControlType = childControl.GetType(); Control newChildControl = (Control)Internals.CreateObjectFromType(childControlType); newChildControl.ID = CreateDynamicWebPartID(childControlType); newWebPart = CreateWebPart(newChildControl); } else { VerifyType(webPart); newWebPart = (WebPart)Internals.CreateObjectFromType(webPart.GetType()); } newWebPart.ID = CreateDynamicWebPartID(webPart.GetType()); return newWebPart; } protected virtual TransformerTypeCollection CreateAvailableTransformers() { TransformerTypeCollection availableTransformers = new TransformerTypeCollection(); WebPartsSection configSection = RuntimeConfig.GetConfig().WebParts; IDictionary transformers = configSection.Transformers.GetTransformerEntries(); foreach (Type type in transformers.Values) { availableTransformers.Add(type); } return availableTransformers; } // Returns an array of ICollection objects. The first is the ConsumerConnectionPoints, the // second is the ProviderConnectionPoints. private static ICollection[] CreateConnectionPoints(Type type) { ArrayList consumerConnectionPoints = new ArrayList(); ArrayList providerConnectionPoints = new ArrayList(); MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); foreach (MethodInfo method in methods) { // Create consumer connection points object[] consumerAttributes = method.GetCustomAttributes(typeof(ConnectionConsumerAttribute), true); // ConnectionConsumerAttribute.AllowMultiple is false Debug.Assert(consumerAttributes.Length == 0 || consumerAttributes.Length == 1); if (consumerAttributes.Length == 1) { // Consumer signature: method is public, return type is void, takes one parameter ParameterInfo[] parameters = method.GetParameters(); Type parameterType = null; if (parameters.Length == 1) { parameterType = parameters[0].ParameterType; } if (method.IsPublic && method.ReturnType == typeof(void) && parameterType != null) { ConnectionConsumerAttribute attribute = consumerAttributes[0] as ConnectionConsumerAttribute; String displayName = attribute.DisplayName; String id = attribute.ID; Type connectionPointType = attribute.ConnectionPointType; bool allowsMultipleConnections = attribute.AllowsMultipleConnections; ConsumerConnectionPoint connectionPoint; if (connectionPointType == null) { connectionPoint = new ConsumerConnectionPoint(method, parameterType, type, displayName, id, allowsMultipleConnections); } else { // The ConnectionPointType is validated in the attribute property getter Object[] args = new Object[] { method, parameterType, type, displayName, id, allowsMultipleConnections }; connectionPoint = (ConsumerConnectionPoint)Activator.CreateInstance(connectionPointType, args); } consumerConnectionPoints.Add(connectionPoint); } else { throw new InvalidOperationException(SR.GetString (SR.WebPartManager_InvalidConsumerSignature, method.Name, type.FullName)); } } // Create provider connection points object[] providerAttributes = method.GetCustomAttributes(typeof(ConnectionProviderAttribute), true); // ConnectionProviderAttribute.AllowMultiple is false Debug.Assert(providerAttributes.Length == 0 || providerAttributes.Length == 1); if (providerAttributes.Length == 1) { // Provider signature: method is public, return type is an object, and takes no parameters Type returnType = method.ReturnType; if (method.IsPublic && returnType != typeof(void) && method.GetParameters().Length == 0) { ConnectionProviderAttribute attribute = providerAttributes[0] as ConnectionProviderAttribute; String displayName = attribute.DisplayName; String id = attribute.ID; Type connectionPointType = attribute.ConnectionPointType; bool allowsMultipleConnections = attribute.AllowsMultipleConnections; ProviderConnectionPoint connectionPoint; if (connectionPointType == null) { connectionPoint = new ProviderConnectionPoint(method, returnType, type, displayName, id, allowsMultipleConnections); } else { // The ConnectionPointType is validated in the attribute property getter Object[] args = new Object[] { method, returnType, type, displayName, id, allowsMultipleConnections }; connectionPoint = (ProviderConnectionPoint)Activator.CreateInstance(connectionPointType, args); } providerConnectionPoints.Add(connectionPoint); } else { throw new InvalidOperationException(SR.GetString (SR.WebPartManager_InvalidProviderSignature, method.Name, type.FullName)); } } } return new ICollection[] { new ConsumerConnectionPointCollection(consumerConnectionPoints), new ProviderConnectionPointCollection(providerConnectionPoints) }; } protected sealed override ControlCollection CreateControlCollection() { return new WebPartManagerControlCollection(this); } /// /// Can be overridden by derived types, to add additional display modes. Display modes /// should be added in the order they are to appear in the page menu. /// protected virtual WebPartDisplayModeCollection CreateDisplayModes() { WebPartDisplayModeCollection displayModes = new WebPartDisplayModeCollection(); displayModes.Add(BrowseDisplayMode); displayModes.Add(CatalogDisplayMode); displayModes.Add(DesignDisplayMode); displayModes.Add(EditDisplayMode); displayModes.Add(ConnectDisplayMode); return displayModes; } private string CreateDisplayTitle(string title, WebPart webPart, int count) { string displayTitle = title; if (webPart.Hidden) { displayTitle = SR.GetString(SR.WebPart_HiddenFormatString, displayTitle); } if (webPart is ErrorWebPart) { displayTitle = SR.GetString(SR.WebPart_ErrorFormatString, displayTitle); } if (count != 0) { if (count < displayTitleSuffix.Length) { displayTitle += displayTitleSuffix[count]; } else { displayTitle += " [" + count.ToString(CultureInfo.CurrentCulture) + "]"; } } return displayTitle; } private IDictionary CreateDisplayTitles() { Hashtable displayTitles = new Hashtable(); Hashtable titles = new Hashtable(); foreach (WebPart part in Controls) { string title = part.Title; if (String.IsNullOrEmpty(title)) { title = SR.GetString(SR.Part_Untitled); } if (part is UnauthorizedWebPart) { displayTitles[part] = title; continue; } ArrayList parts = (ArrayList)titles[title]; if (parts == null) { parts = new ArrayList(); titles[title] = parts; displayTitles[part] = CreateDisplayTitle(title, part, 0); } else { int count = parts.Count; if (count == 1) { WebPart firstPart = (WebPart)parts[0]; displayTitles[firstPart] = CreateDisplayTitle(title, firstPart, 1); } displayTitles[part] = CreateDisplayTitle(title, part, count + 1); } parts.Add(part); } return displayTitles; } protected virtual string CreateDynamicConnectionID() { Debug.Assert(Personalization.IsModifiable); // int guidHash = Math.Abs(Guid.NewGuid().GetHashCode()); return DynamicConnectionIDPrefix + guidHash.ToString(CultureInfo.InvariantCulture); } protected virtual string CreateDynamicWebPartID(Type webPartType) { if (webPartType == null) { throw new ArgumentNullException("webPartType"); } Debug.Assert(Personalization.IsModifiable); // int guidHash = Math.Abs(Guid.NewGuid().GetHashCode()); string id = DynamicWebPartIDPrefix + guidHash.ToString(CultureInfo.InvariantCulture); if (Page != null && Page.Trace.IsEnabled) { id += webPartType.Name; } return id; } protected virtual ErrorWebPart CreateErrorWebPart(string originalID, string originalTypeName, string originalPath, string genericWebPartID, string errorMessage) { ErrorWebPart errorWebPart = new ErrorWebPart(originalID, originalTypeName, originalPath, genericWebPartID); errorWebPart.ErrorMessage = errorMessage; return errorWebPart; } /// /// protected virtual WebPartPersonalization CreatePersonalization() { return new WebPartPersonalization(this); } /// /// Wraps the control in a GenericWebPart, and returns the GenericWebPart. Virtual so it can be /// overridden to use a derived type of GenericWebPart instead. Needs to be public so it can /// be called by the page developer. /// public virtual GenericWebPart CreateWebPart(Control control) { return CreateWebPartStatic(control); } // Called by other WebParts classes to create a GenericWebPart, if they do not have // a reference to a WebPartManager (i.e. at design time). This method centralizes // the creation of GenericWebParts. internal static GenericWebPart CreateWebPartStatic(Control control) { GenericWebPart genericWebPart = new GenericWebPart(control); // The ChildControl should be added to the GenericWebPart.Controls collection when CreateWebPart() // is called, instead of waiting until the GenericWebPart.Controls collection is accessed. // This is necessary since the caller has a direct reference to the ChildControl, and may // perform operations on the ChildControl that assume the ChildControl is parented. // (VSWhidbey 498039) genericWebPart.CreateChildControls(); return genericWebPart; } public void DeleteWebPart(WebPart webPart) { CloseOrDeleteWebPart(webPart, /* delete */ true); } // Disconnects all connections involving the Web Part protected virtual void DisconnectWebPart(WebPart webPart) { try { // We cannot allow any of the WebPartsDisconnecting events to be cancelled, since we may have already // disconnected some connections before we hit the one that needs to be cancelled. (VSWhidbey 516012) _allowEventCancellation = false; foreach (WebPartConnection connection in Connections) { if (connection.Provider == webPart || connection.Consumer == webPart) { DisconnectWebParts(connection); } } } finally { _allowEventCancellation = true; } } public virtual void DisconnectWebParts(WebPartConnection connection) { Personalization.EnsureEnabled(/* ensureModifiable */ true); if (connection == null) { throw new ArgumentNullException("connection"); } Debug.Assert(!(StaticConnections.Contains(connection) && DynamicConnections.Contains(connection))); WebPart provider = connection.Provider; ProviderConnectionPoint providerConnectionPoint = connection.ProviderConnectionPoint; WebPart consumer = connection.Consumer; ConsumerConnectionPoint consumerConnectionPoint = connection.ConsumerConnectionPoint; WebPartConnectionsCancelEventArgs ce = new WebPartConnectionsCancelEventArgs( provider, providerConnectionPoint, consumer, consumerConnectionPoint, connection); OnWebPartsDisconnecting(ce); if (_allowEventCancellation && ce.Cancel) { return; } WebPartConnectionsEventArgs eventArgs = new WebPartConnectionsEventArgs( provider, providerConnectionPoint, consumer, consumerConnectionPoint); if (StaticConnections.Contains(connection)) { if (StaticConnections.IsReadOnly) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DisconnectTooLate)); } if (Internals.ConnectionDeleted(connection)) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_AlreadyDisconnected)); } Internals.DeleteConnection(connection); _hasDataChanged = true; OnWebPartsDisconnected(eventArgs); } else if (DynamicConnections.Contains(connection)) { if (DynamicConnections.IsReadOnly) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DisconnectTooLate)); } if (ShouldRemoveConnection(connection)) { // Unshared dynamic connection should never be disabled Debug.Assert(!Internals.ConnectionDeleted(connection)); DynamicConnections.Remove(connection); } else { if (Internals.ConnectionDeleted(connection)) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_AlreadyDisconnected)); } Internals.DeleteConnection(connection); } _hasDataChanged = true; OnWebPartsDisconnected(eventArgs); } else { throw new ArgumentException(SR.GetString(SR.WebPartManager_UnknownConnection), "connection"); } } public virtual void EndWebPartConnecting() { Personalization.EnsureEnabled(/* ensureModifiable */ true); WebPart selectedWebPart = SelectedWebPart; if (selectedWebPart == null) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoSelectedWebPartConnect)); } WebPartCancelEventArgs ce = new WebPartCancelEventArgs(selectedWebPart); OnSelectedWebPartChanging(ce); if (_allowEventCancellation && ce.Cancel) { return; } SetSelectedWebPart(null); Internals.CallOnConnectModeChanged(selectedWebPart); // The EventArg should always contain the new SelectedWebPart, so it should contain null // when we are ending connecting. OnSelectedWebPartChanged(new WebPartEventArgs(null)); } public virtual void EndWebPartEditing() { Personalization.EnsureEnabled(/* ensureModifiable */ true); WebPart selectedWebPart = SelectedWebPart; if (selectedWebPart == null) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoSelectedWebPartEdit)); } WebPartCancelEventArgs ce = new WebPartCancelEventArgs(selectedWebPart); OnSelectedWebPartChanging(ce); if (_allowEventCancellation && ce.Cancel) { return; } SetSelectedWebPart(null); Internals.CallOnEditModeChanged(selectedWebPart); // The EventArg should always contain the new SelectedWebPart, so it should contain null // when we are ending editing. OnSelectedWebPartChanged(new WebPartEventArgs(null)); } public virtual void ExportWebPart(WebPart webPart, XmlWriter writer) { // Personalization.EnsureEnabled(/* ensureModifiable */ false); if (webPart == null) { throw new ArgumentNullException("webPart"); } if (!Controls.Contains(webPart)) { throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart"); } if (writer == null) { throw new ArgumentNullException("writer"); } if (webPart.ExportMode == WebPartExportMode.None) { throw new ArgumentException(SR.GetString(SR.WebPartManager_PartNotExportable), "webPart"); } bool excludeSensitive = (webPart.ExportMode == WebPartExportMode.NonSensitiveData && !(Personalization.Scope == PersonalizationScope.Shared)); // Write the root elements writer.WriteStartElement(ExportRootElement); writer.WriteStartElement(ExportPartElement); writer.WriteAttributeString(ExportPartNamespaceAttribute, ExportPartNamespaceValue); // Write metadata writer.WriteStartElement(ExportMetaDataElement); writer.WriteStartElement(ExportTypeElement); Control control = webPart.ToControl(); UserControl userControl = control as UserControl; if (userControl != null) { writer.WriteAttributeString(ExportUserControlSrcAttribute, userControl.AppRelativeVirtualPath); } else { writer.WriteAttributeString(ExportTypeNameAttribute, WebPartUtil.SerializeType(control.GetType())); } writer.WriteEndElement(); //type writer.WriteElementString(ExportErrorMessageElement, webPart.ImportErrorMessage); writer.WriteEndElement(); //metadata // Write the data writer.WriteStartElement(ExportDataElement); // We get the personalization data for the current page personalization mode IDictionary propBag = PersonalizableAttribute.GetPersonalizablePropertyValues(webPart, PersonalizationScope.Shared, excludeSensitive); writer.WriteStartElement(ExportPropertiesElement); // Special case GenericWebPart GenericWebPart genericWebPart = webPart as GenericWebPart; if (genericWebPart != null) { // Export IPersonalizable user control data first ExportIPersonalizable(writer, control, excludeSensitive); IDictionary controlData = PersonalizableAttribute.GetPersonalizablePropertyValues(control, PersonalizationScope.Shared, excludeSensitive); ExportToWriter(controlData, writer); writer.WriteEndElement(); //properties writer.WriteStartElement(ExportGenericPartPropertiesElement); // Export IPersonalizable part data first ExportIPersonalizable(writer, webPart, excludeSensitive); ExportToWriter(propBag, writer); } else { // Export IPersonalizable part data first ExportIPersonalizable(writer, webPart, excludeSensitive); ExportToWriter(propBag, writer); } writer.WriteEndElement(); //properties or genericWebPartProperties writer.WriteEndElement(); //data writer.WriteEndElement(); //webpart writer.WriteEndElement(); //webparts } private void ExportIPersonalizable(XmlWriter writer, Control control, bool excludeSensitive) { IPersonalizable personalizableControl = control as IPersonalizable; if (personalizableControl != null) { PersonalizationDictionary personalizableData = new PersonalizationDictionary(); personalizableControl.Save(personalizableData); if (personalizableData.Count > 0) { writer.WriteStartElement(ExportIPersonalizableElement); ExportToWriter(personalizableData, writer, /* isIPersonalizable */ true, excludeSensitive); writer.WriteEndElement(); // ipersonalizable } } } private static void ExportProperty(XmlWriter writer, string name, string value, Type type, PersonalizationScope scope, bool isIPersonalizable) { writer.WriteStartElement(ExportPropertyElement); writer.WriteAttributeString(ExportPropertyNameAttribute, name); writer.WriteAttributeString(ExportPropertyTypeAttribute, GetExportName(type)); if (isIPersonalizable) { writer.WriteAttributeString(ExportPropertyScopeAttribute, scope.ToString()); } if (value == null) { writer.WriteAttributeString(ExportPropertyNullAttribute, "true"); } else { writer.WriteString(value); } writer.WriteEndElement(); //property } private void ExportToWriter(IDictionary propBag, XmlWriter writer) { ExportToWriter(propBag, writer, false, false); } private void ExportToWriter(IDictionary propBag, XmlWriter writer, bool isIPersonalizable, bool excludeSensitive) { // We only honor excludeSensitive if isIpersonalizable is true. Debug.Assert((!excludeSensitive) || isIPersonalizable); // Work on each property in the persomalization data foreach(DictionaryEntry entry in propBag) { string name = (string)entry.Key; if (name == AuthorizationFilterName || name == ImportErrorMessageName) { continue; } PropertyInfo pi = null; object val = null; Pair data = entry.Value as Pair; PersonalizationScope scope = PersonalizationScope.User; // We expect a pair if not exporting types // (which happens only for non-IPersonalizable data) if (isIPersonalizable == false && data != null) { pi = (PropertyInfo)data.First; val = data.Second; } else if (isIPersonalizable) { PersonalizationEntry personalizationEntry = entry.Value as PersonalizationEntry; if (personalizationEntry != null && (Personalization.Scope == PersonalizationScope.Shared || personalizationEntry.Scope == PersonalizationScope.User)) { val = personalizationEntry.Value; scope = personalizationEntry.Scope; } if (excludeSensitive && personalizationEntry.IsSensitive) { continue; } } // we get the type from the PropertyInfo if we have it, or from the value if it's not null, or we use object. Type valType = ((pi != null) ? pi.PropertyType : ((val != null) ? val.GetType() : typeof(object))); string exportString; if (ShouldExportProperty(pi, valType, val, out exportString)) { ExportProperty(writer, name, exportString, valType, scope, isIPersonalizable); } } } [ EditorBrowsable(EditorBrowsableState.Never), ] public override void Focus() { throw new NotSupportedException(SR.GetString(SR.NoFocusSupport, this.GetType().Name)); } /// /// Returns all the web parts in a zone, excluding closed web parts. /// Since this is only a private method, return an IList instead of a WebPartCollection /// for better performance. /// private IList GetAllWebPartsForZone(WebPartZoneBase zone) { if (_partsForZone == null) { _partsForZone = new HybridDictionary(true /* caseInsensitive */); foreach (WebPart part in Controls) { if (!part.IsClosed) { string zoneID = Internals.GetZoneID(part); Debug.Assert(!String.IsNullOrEmpty(zoneID)); if (!String.IsNullOrEmpty(zoneID)) { SortedList partsForZone = (SortedList)_partsForZone[zoneID]; if (partsForZone == null) { partsForZone = new SortedList(new WebPart.ZoneIndexComparer()); _partsForZone[zoneID] = partsForZone; } partsForZone.Add(part, null); } } } } SortedList parts = (SortedList)_partsForZone[zone.ID]; if (parts == null) { parts = new SortedList(); } return parts.GetKeyList(); } private static ICollection[] GetConnectionPoints(Type type) { if (ConnectionPointsCache == null) { // I don't think there is a race condition here. Even if multiple threads enter this block // at the same time, the worst thing that can happen is that the ConnectionPointsCache gets // replaced by a new Hashtable(), and existing entries will need to be recomputed. // There is no way for the ConnectionPointsCache to become null. ConnectionPointsCache = Hashtable.Synchronized(new Hashtable()); } // DevDiv Bugs 38677: Cache by culture and type as it may vary by culture within this app ConnectionPointKey connectionPointKey = new ConnectionPointKey(type, CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture); ICollection[] connectionPoints = (ICollection[])ConnectionPointsCache[connectionPointKey]; if (connectionPoints == null) { connectionPoints = CreateConnectionPoints(type); ConnectionPointsCache[connectionPointKey] = connectionPoints; } return connectionPoints; } internal ConsumerConnectionPoint GetConsumerConnectionPoint(WebPart webPart, string connectionPointID) { ConsumerConnectionPointCollection points = GetConsumerConnectionPoints(webPart); if (points != null && points.Count > 0) { return points[connectionPointID]; } else { return null; } } public virtual ConsumerConnectionPointCollection GetConsumerConnectionPoints(WebPart webPart) { if (webPart == null) { throw new ArgumentNullException("webPart"); } // Do not check that Controls.Contains(webPart), since this may be called on a WebPart // outside of a Zone. Also, this method shouldn't really care whether the WebPart is // inside the WebPartManager. return GetConsumerConnectionPoints(webPart.ToControl().GetType()); } private static ConsumerConnectionPointCollection GetConsumerConnectionPoints(Type type) { ICollection[] connectionPoints = GetConnectionPoints(type); return (ConsumerConnectionPointCollection)connectionPoints[0]; } public static WebPartManager GetCurrentWebPartManager(Page page) { if (page == null) { throw new ArgumentNullException("page"); } return page.Items[typeof(WebPartManager)] as WebPartManager; } // Before PreRender, return String.Empty. // On first call to this function after PreRender, compute DisplayTitle for all WebParts // and save it in a dictionary. WebPart.DisplayTitle is nonvirtual and calls this method every time. // A derived WebPartManager can override this method to compute and store DisplayTitle any way it // sees fit. It could compute the values sooner than PreRender. protected internal virtual string GetDisplayTitle(WebPart webPart) { if (webPart == null) { throw new ArgumentNullException("webPart"); } if (!Controls.Contains(webPart)) { throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart"); } if (!_allowCreateDisplayTitles) { return String.Empty; } if (_displayTitles == null) { _displayTitles = CreateDisplayTitles(); } string displayTitle = (string)_displayTitles[webPart]; Debug.Assert(!String.IsNullOrEmpty(displayTitle)); return displayTitle; } private static ICollection GetEnabledConnectionPoints(ICollection connectionPoints, WebPart webPart) { Control control = webPart.ToControl(); ArrayList enabledPoints = new ArrayList(); foreach (ConnectionPoint point in connectionPoints) { if (point.GetEnabled(control)) { enabledPoints.Add(point); } } return enabledPoints; } internal ConsumerConnectionPointCollection GetEnabledConsumerConnectionPoints(WebPart webPart) { ICollection enabledPoints = GetEnabledConnectionPoints(GetConsumerConnectionPoints(webPart), webPart); return new ConsumerConnectionPointCollection(enabledPoints); } internal ProviderConnectionPointCollection GetEnabledProviderConnectionPoints(WebPart webPart) { ICollection enabledPoints = GetEnabledConnectionPoints(GetProviderConnectionPoints(webPart), webPart); return new ProviderConnectionPointCollection(enabledPoints); } public string GetExportUrl(WebPart webPart) { string personalizationScope = (Personalization.Scope == PersonalizationScope.Shared) ? "&scope=shared" : String.Empty; string queryString = Page.Request.QueryStringText; return Page.Request.FilePath + "?" + Page.WebPartExportID + "=true&webPart=" + HttpUtility.UrlEncode(webPart.ID) + (!String.IsNullOrEmpty(queryString) ? "&query=" + HttpUtility.UrlEncode(queryString) : String.Empty) + personalizationScope; } private static Type GetExportType(string name) { switch (name) { case ExportTypeString: return typeof(string); case ExportTypeInt: return typeof(int); case ExportTypeBool: return typeof(bool); case ExportTypeDouble: return typeof(double); case ExportTypeSingle: return typeof(Single); case ExportTypeDateTime: return typeof(DateTime); case ExportTypeColor: return typeof(Color); case ExportTypeUnit: return typeof(Unit); case ExportTypeFontSize: return typeof(FontSize); case ExportTypeDirection: return typeof(ContentDirection); case ExportTypeHelpMode: return typeof(WebPartHelpMode); case ExportTypeChromeState: return typeof(PartChromeState); case ExportTypeChromeType: return typeof(PartChromeType); case ExportTypeExportMode: return typeof(WebPartExportMode); case ExportTypeObject: return typeof(object); default: return WebPartUtil.DeserializeType(name, false); } } private static string GetExportName(Type type) { if (type == typeof(string)) { return ExportTypeString; } else if (type == typeof(int)) { return ExportTypeInt; } else if (type == typeof(bool)) { return ExportTypeBool; } else if (type == typeof(double)) { return ExportTypeDouble; } else if (type == typeof(Single)) { return ExportTypeSingle; } else if (type == typeof(DateTime)) { return ExportTypeDateTime; } else if (type == typeof(Color)) { return ExportTypeColor; } else if (type == typeof(Unit)) { return ExportTypeUnit; } else if (type == typeof(FontSize)) { return ExportTypeFontSize; } else if (type == typeof(ContentDirection)) { return ExportTypeDirection; } else if (type == typeof(WebPartHelpMode)) { return ExportTypeHelpMode; } else if (type == typeof(PartChromeState)) { return ExportTypeChromeState; } else if (type == typeof(PartChromeType)) { return ExportTypeChromeType; } else if (type == typeof(WebPartExportMode)) { return ExportTypeExportMode; } else if (type == typeof(object)) { return ExportTypeObject; } else { return type.AssemblyQualifiedName; } } /// /// Used by the page developer to get a reference to the WebPart that contains a control /// placed in a WebPartZone. Returns null if the control is not inside a WebPart. /// public GenericWebPart GetGenericWebPart(Control control) { if (control == null) { throw new ArgumentNullException("control"); } // PERF: First check the parent of the control, before looping through all GenericWebParts Control parent = control.Parent; GenericWebPart genericParent = parent as GenericWebPart; if (genericParent != null && genericParent.ChildControl == control) { return genericParent; } else { foreach (WebPart part in Controls) { GenericWebPart genericPart = part as GenericWebPart; if (genericPart != null && genericPart.ChildControl == control) { return genericPart; } } } return null; } internal ProviderConnectionPoint GetProviderConnectionPoint(WebPart webPart, string connectionPointID) { ProviderConnectionPointCollection points = GetProviderConnectionPoints(webPart); if (points != null && points.Count > 0) { return points[connectionPointID]; } else { return null; } } public virtual ProviderConnectionPointCollection GetProviderConnectionPoints(WebPart webPart) { if (webPart == null) { throw new ArgumentNullException("webPart"); } // Do not check that Controls.Contains(webPart), since this may be called on a WebPart // outside of a Zone. Also, this method shouldn't really care whether the WebPart is // inside the WebPartManager. return GetProviderConnectionPoints(webPart.ToControl().GetType()); } private static ProviderConnectionPointCollection GetProviderConnectionPoints(Type type) { ICollection[] connectionPoints = GetConnectionPoints(type); return (ProviderConnectionPointCollection)connectionPoints[1]; } /// /// Returns the web parts that should currently be rendered by the zone. It is important that /// this method filter out any web parts that will not be rendered by the zone, otherwise /// the AddWebPart method will not work correctly (VSWhidbey 77719) /// internal WebPartCollection GetWebPartsForZone(WebPartZoneBase zone) { if (zone == null) { throw new ArgumentNullException("zone"); } if (_webPartZones.Contains(zone) == false) { throw new ArgumentException(SR.GetString(SR.WebPartManager_MustRegister), "zone"); } IList allWebPartsForZone = GetAllWebPartsForZone(zone); WebPartCollection webParts = new WebPartCollection(); if (allWebPartsForZone.Count > 0) { foreach (WebPart part in allWebPartsForZone) { if (ShouldRenderWebPartInZone(part, zone)) { webParts.Add(part); } } } return webParts; } /// /// If the WebPart is a consumer on the given connection point, returns the corresponding connection. /// Else, returns null. /// internal WebPartConnection GetConnectionForConsumer(WebPart consumer, ConsumerConnectionPoint connectionPoint) { ConsumerConnectionPoint actualConnectionPoint = connectionPoint; // if (connectionPoint == null) { actualConnectionPoint = GetConsumerConnectionPoint(consumer, null); } // PERF: Use the StaticConnections and DynamicConnections collections separately, instead // of using the Connections property which is created on every call. foreach (WebPartConnection connection in StaticConnections) { if (!Internals.ConnectionDeleted(connection) && connection.Consumer == consumer) { ConsumerConnectionPoint c = GetConsumerConnectionPoint(consumer, connection.ConsumerConnectionPointID); if (c == actualConnectionPoint) { return connection; } } } foreach (WebPartConnection connection in DynamicConnections) { if (!Internals.ConnectionDeleted(connection) && connection.Consumer == consumer) { ConsumerConnectionPoint c = GetConsumerConnectionPoint(consumer, connection.ConsumerConnectionPointID); if (c == actualConnectionPoint) { return connection; } } } return null; } /// /// If the WebPart is a provider on the given connection point, returns the corresponding connection. /// Else, returns null. /// internal WebPartConnection GetConnectionForProvider(WebPart provider, ProviderConnectionPoint connectionPoint) { ProviderConnectionPoint actualConnectionPoint = connectionPoint; if (connectionPoint == null) { actualConnectionPoint = GetProviderConnectionPoint(provider, null); } // PERF: Use the StaticConnections and DynamicConnections collections separately, instead // of using the Connections property which is created on every call. foreach (WebPartConnection connection in StaticConnections) { if (!Internals.ConnectionDeleted(connection) && connection.Provider == provider) { ProviderConnectionPoint c = GetProviderConnectionPoint(provider, connection.ProviderConnectionPointID); if (c == actualConnectionPoint) { return connection; } } } foreach (WebPartConnection connection in DynamicConnections) { if (!Internals.ConnectionDeleted(connection) && connection.Provider == provider) { ProviderConnectionPoint c = GetProviderConnectionPoint(provider, connection.ProviderConnectionPointID); if (c == actualConnectionPoint) { return connection; } } } return null; } private static void ImportReadTo(XmlReader reader, string elementToFind) { while (reader.Name != elementToFind) { if (!reader.Read()) { throw new XmlException(); } } } private static void ImportReadTo(XmlReader reader, string elementToFindA, string elementToFindB) { while (reader.Name != elementToFindA && reader.Name != elementToFindB) { if (!reader.Read()) { throw new XmlException(); } } } private static void ImportSkipTo(XmlReader reader, string elementToFind) { while (reader.Name != elementToFind) { reader.Skip(); if (reader.EOF) { throw new XmlException(); } } } /// /// Never throws except for null arguments. Returns an error message in the out parameter instead. /// [[....]] I investigated whether this could be refactored to share common code with /// LoadDynamicWebPart(), but it seems the methods are too different. /// public virtual WebPart ImportWebPart(XmlReader reader, out string errorMessage) { Personalization.EnsureEnabled(/* ensureModifiable */ true); if (reader == null) { throw new ArgumentNullException("reader"); } MinimalPermissionSet.PermitOnly(); bool permitOnly = true; string importErrorMessage = string.Empty; // Extra try-catch block to prevent elevation of privilege attack via exception filter try { try { // Get to the metadata reader.MoveToContent(); reader.ReadStartElement(ExportRootElement); ImportSkipTo(reader, ExportPartElement); // Check the version on the webPart element string version = reader.GetAttribute(ExportPartNamespaceAttribute); if (String.IsNullOrEmpty(version)) { errorMessage = SR.GetString(SR.WebPart_ImportErrorNoVersion); return null; } if (!String.Equals(version, ExportPartNamespaceValue, StringComparison.OrdinalIgnoreCase)) { errorMessage = SR.GetString(SR.WebPart_ImportErrorInvalidVersion); return null; } ImportReadTo(reader, ExportMetaDataElement); reader.ReadStartElement(ExportMetaDataElement); // Get the type name string partTypeName = null; string userControlTypeName = null; ImportSkipTo(reader, ExportTypeElement); partTypeName = reader.GetAttribute(ExportTypeNameAttribute); userControlTypeName = reader.GetAttribute(ExportUserControlSrcAttribute); // Get the error message to display if unsuccessful to load the type ImportSkipTo(reader, ExportErrorMessageElement); importErrorMessage = reader.ReadElementString(); // Get a type object from the type name Type partType; WebPart part = null; Control childControl = null; try { // If we are in shared scope, we are importing a shared WebPart bool isShared = (Personalization.Scope == PersonalizationScope.Shared); if (!String.IsNullOrEmpty(partTypeName)) { CodeAccessPermission.RevertPermitOnly(); permitOnly = false; MediumPermissionSet.PermitOnly(); permitOnly = true; partType = WebPartUtil.DeserializeType(partTypeName, true); CodeAccessPermission.RevertPermitOnly(); permitOnly = false; MinimalPermissionSet.PermitOnly(); permitOnly = true; // First check if the type is authorized if (!IsAuthorized(partType, null, null, isShared)) { errorMessage = SR.GetString(SR.WebPartManager_ForbiddenType); return null; } // If the type is not a webpart, create a generic Web Part if (!partType.IsSubclassOf(typeof(WebPart))) { if (!partType.IsSubclassOf(typeof(Control))) { // We only allow for Controls (VSWhidbey 428511) errorMessage = SR.GetString(SR.WebPartManager_TypeMustDeriveFromControl); return null; } // Create an instance of the object childControl = (Control)(Internals.CreateObjectFromType(partType)); childControl.ID = CreateDynamicWebPartID(partType); part = CreateWebPart(childControl); } else { // Create an instance of the object part = (WebPart)(Internals.CreateObjectFromType(partType)); } } else { // Instantiate a user control in a generic web part // Check if the path is authorized if (!IsAuthorized(typeof(UserControl), userControlTypeName, null, isShared)) { errorMessage = SR.GetString(SR.WebPartManager_ForbiddenType); return null; } CodeAccessPermission.RevertPermitOnly(); permitOnly = false; childControl = Page.LoadControl(userControlTypeName); partType = childControl.GetType(); MinimalPermissionSet.PermitOnly(); permitOnly = true; childControl.ID = CreateDynamicWebPartID(partType); part = CreateWebPart(childControl); } } catch { if (!String.IsNullOrEmpty(importErrorMessage)) { errorMessage = importErrorMessage; } else { errorMessage = SR.GetString(SR.WebPartManager_ErrorLoadingWebPartType); } return null; } // Set default error message for all subsequent errors if (String.IsNullOrEmpty(importErrorMessage)) { importErrorMessage = SR.GetString(SR.WebPart_DefaultImportErrorMessage); } // Get to the data ImportSkipTo(reader, ExportDataElement); reader.ReadStartElement(ExportDataElement); ImportSkipTo(reader, ExportPropertiesElement); if (!reader.IsEmptyElement) { reader.ReadStartElement(ExportPropertiesElement); // Special-case IPersonalizable controls // ImportFromReader will set the right permission set when appropriate, reverting before we call CodeAccessPermission.RevertPermitOnly(); permitOnly = false; ImportIPersonalizable(reader, (childControl != null ? childControl : part)); MinimalPermissionSet.PermitOnly(); permitOnly = true; } // Set property values from XML description IDictionary personalizableProperties; if (childControl != null) { if (!reader.IsEmptyElement) { // Get the collection of personalizable properties for the child control personalizableProperties = PersonalizableAttribute.GetPersonalizablePropertyEntries(partType); // Copied from below. We must also execute this code when parsing the ChildControl // IPersonalizable and Personalizable properties. while (reader.Name != ExportPropertyElement) { reader.Skip(); if (reader.EOF) { errorMessage = null; return part; } } // ImportFromReader will set the right permission set when appropriate, reverting before we call CodeAccessPermission.RevertPermitOnly(); permitOnly = false; ImportFromReader(personalizableProperties, childControl, reader); MinimalPermissionSet.PermitOnly(); permitOnly = true; } // And then for the generic WebPart ImportSkipTo(reader, ExportGenericPartPropertiesElement); reader.ReadStartElement(ExportGenericPartPropertiesElement); // ImportFromReader will set the right permission set when appropriate, reverting before we call CodeAccessPermission.RevertPermitOnly(); permitOnly = false; ImportIPersonalizable(reader, part); MinimalPermissionSet.PermitOnly(); permitOnly = true; personalizableProperties = PersonalizableAttribute.GetPersonalizablePropertyEntries(part.GetType()); } else { // Get the collection of personalizable properties personalizableProperties = PersonalizableAttribute.GetPersonalizablePropertyEntries(partType); } while (reader.Name != ExportPropertyElement) { reader.Skip(); if (reader.EOF) { errorMessage = null; return part; } } // ImportFromReader will set the right permission set when appropriate, reverting before we call CodeAccessPermission.RevertPermitOnly(); permitOnly = false; ImportFromReader(personalizableProperties, part, reader); MinimalPermissionSet.PermitOnly(); permitOnly = true; errorMessage = null; // Return imported part return part; } catch (XmlException) { errorMessage = SR.GetString(SR.WebPartManager_ImportInvalidFormat); return null; } catch (Exception e) { if ((Context != null) && (Context.IsCustomErrorEnabled)) { errorMessage = (importErrorMessage.Length != 0) ? importErrorMessage : SR.GetString(SR.WebPart_DefaultImportErrorMessage); } else { errorMessage = e.Message; } return null; } finally { if (permitOnly) { // revert if you're not just exiting the stack frame anyway CodeAccessPermission.RevertPermitOnly(); } } } catch { throw; } } private void ImportIPersonalizable(XmlReader reader, Control control) { if (control is IPersonalizable) { // The control may implement IPersonalizable, but the .WebPart file may not contain // an "ipersonalizable" element. The WebPart may have returned no data from its // IPersonalizable.Save() method, or the WebPart may have been recently changed to // implement IPersonalizable. This are valid scenarios, so we should not require // the XML to contain the "ipersonalizable" element. (VSWhidbey 499016) // Read to the next element that is either "property" or "ipersonalizable". ImportReadTo(reader, ExportIPersonalizableElement, ExportPropertyElement); // If the next element is "ipersonalizable", then we import the IPersonalizable data. // Else, we do nothing, and the current "property" element will be imported as a standard // personalizable property. if (reader.Name == ExportIPersonalizableElement) { // Create a dictionary from the XML description reader.ReadStartElement(ExportIPersonalizableElement); ImportFromReader(null, control, reader); } } } private void ImportFromReader(IDictionary personalizableProperties, Control target, XmlReader reader) { Debug.Assert(target != null); ImportReadTo(reader, ExportPropertyElement); MinimalPermissionSet.PermitOnly(); bool permitOnly = true; try { try { IDictionary properties; if (personalizableProperties != null) { properties = new HybridDictionary(); } else { properties = new PersonalizationDictionary(); } // Set properties from the xml document while (reader.Name == ExportPropertyElement) { // Get the name of the property string propertyName = reader.GetAttribute(ExportPropertyNameAttribute); string typeName = reader.GetAttribute(ExportPropertyTypeAttribute); string scope = reader.GetAttribute(ExportPropertyScopeAttribute); bool isNull = String.Equals( reader.GetAttribute(ExportPropertyNullAttribute), "true", StringComparison.OrdinalIgnoreCase); // Do not import Zone information or AuthorizationFilter or custom data if (propertyName == AuthorizationFilterName || propertyName == ZoneIDName || propertyName == ZoneIndexName) { reader.ReadElementString(); if (!reader.Read()) { throw new XmlException(); } } else { string valString = reader.ReadElementString(); object val = null; bool valueComputed = false; PropertyInfo pi = null; if (personalizableProperties != null) { // Get the relevant personalizable property on the target (no need to check the property is personalizable) PersonalizablePropertyEntry entry = (PersonalizablePropertyEntry)(personalizableProperties[propertyName]); if (entry != null) { pi = entry.PropertyInfo; Debug.Assert(pi != null); // If the property is a url, validate protocol (VSWhidbey 290418) UrlPropertyAttribute urlAttr = Attribute.GetCustomAttribute(pi, typeof(UrlPropertyAttribute), true) as UrlPropertyAttribute; if (urlAttr != null && CrossSiteScriptingValidation.IsDangerousUrl(valString)) { throw new InvalidDataException(SR.GetString(SR.WebPart_BadUrl, valString)); } } } Type type = null; if (!String.IsNullOrEmpty(typeName)) { // Need medium trust to call BuildManager.GetType() CodeAccessPermission.RevertPermitOnly(); permitOnly = false; MediumPermissionSet.PermitOnly(); permitOnly = true; type = GetExportType(typeName); CodeAccessPermission.RevertPermitOnly(); permitOnly = false; MinimalPermissionSet.PermitOnly(); permitOnly = true; } if ((pi != null) && ((pi.PropertyType == type) || (type == null))) { // Look at the target property // See if the property itself has a type converter associated with it TypeConverterAttribute attr = Attribute.GetCustomAttribute(pi, typeof(TypeConverterAttribute), true) as TypeConverterAttribute; if (attr != null) { // Need medium trust to call BuildManager.GetType() CodeAccessPermission.RevertPermitOnly(); permitOnly = false; MediumPermissionSet.PermitOnly(); permitOnly = true; Type converterType = WebPartUtil.DeserializeType(attr.ConverterTypeName, false); CodeAccessPermission.RevertPermitOnly(); permitOnly = false; MinimalPermissionSet.PermitOnly(); permitOnly = true; // SECURITY: Check that the type is a subclass of TypeConverter before instantiating. if (converterType != null && converterType.IsSubclassOf(typeof(TypeConverter))) { TypeConverter converter = (TypeConverter)(Internals.CreateObjectFromType(converterType)); if (Util.CanConvertToFrom(converter, typeof(string))) { if (!isNull) { val = converter.ConvertFromInvariantString(valString); } valueComputed = true; } } } // Then, look at the converters on the property type if (!valueComputed) { // Use the type converter associated with the type itself TypeConverter converter = TypeDescriptor.GetConverter(pi.PropertyType); if (Util.CanConvertToFrom(converter, typeof(string))) { if (!isNull) { val = converter.ConvertFromInvariantString(valString); } valueComputed = true; // Not importing anything else for security reasons } } } // finally, use the XML-specified type if (!valueComputed && (type != null)) { // Look at the XML-declared type if (type == typeof(string)) { if (!isNull) { val = valString; } valueComputed = true; } else { TypeConverter typeConverter = TypeDescriptor.GetConverter(type); if (Util.CanConvertToFrom(typeConverter, typeof(string))) { if (!isNull) { val = typeConverter.ConvertFromInvariantString(valString); } valueComputed = true; } } } // Always want to import a null IPersonalizable value, since we will never have a type // converter for the value. However, we should not import a null Personalizable value // unless the PropertyInfo had a type converter, since the property may be a value type // that cannot accept null as a value. (VSWhidbey 537895) if (isNull && personalizableProperties == null) { valueComputed = true; } // Now we should have a value (val) if (valueComputed) { if (personalizableProperties != null) { properties.Add(propertyName, val); } else { // Determine scope: PersonalizationScope personalizationScope = String.Equals(scope, PersonalizationScope.Shared.ToString(), StringComparison.OrdinalIgnoreCase) ? PersonalizationScope.Shared : PersonalizationScope.User; properties.Add(propertyName, new PersonalizationEntry(val, personalizationScope)); } } else { throw new HttpException(SR.GetString(SR.WebPartManager_ImportInvalidData, propertyName)); } } while (reader.Name != ExportPropertyElement) { if (reader.EOF || (reader.Name == ExportGenericPartPropertiesElement) || (reader.Name == ExportPropertiesElement) || ((reader.Name == ExportIPersonalizableElement) && (reader.NodeType == XmlNodeType.EndElement))) { goto EndOfData; } reader.Skip(); } } EndOfData: if (personalizableProperties != null) { IDictionary unused = BlobPersonalizationState.SetPersonalizedProperties(target, properties); if ((unused != null) && (unused.Count > 0)) { IVersioningPersonalizable versioningTarget = target as IVersioningPersonalizable; if (versioningTarget != null) { versioningTarget.Load(unused); } } } else { Debug.Assert(target is IPersonalizable); ((IPersonalizable)target).Load((PersonalizationDictionary)properties); } } finally { if (permitOnly) { // revert if you're not just exiting the stack frame anyway CodeAccessPermission.RevertPermitOnly(); } } } catch { throw; } } public virtual bool IsAuthorized(Type type, string path, string authorizationFilter, bool isShared) { if (type == null) { throw new ArgumentNullException("type"); } if (type == typeof(UserControl)) { if (String.IsNullOrEmpty(path)) { throw new ArgumentException(SR.GetString(SR.WebPartManager_PathCannotBeEmpty)); } } else { if (!String.IsNullOrEmpty(path)) { throw new ArgumentException(SR.GetString(SR.WebPartManager_PathMustBeEmpty, path)); } } WebPartAuthorizationEventArgs auth = new WebPartAuthorizationEventArgs(type, path, authorizationFilter, isShared); OnAuthorizeWebPart(auth); return auth.IsAuthorized; } public bool IsAuthorized(WebPart webPart) { if (webPart == null) { throw new ArgumentNullException("webPart"); } // Do not check that Controls.Contains(webPart), since this will be called on a WebPart // before it is added to the Controls collection. // Calculate authorizationFilter from property value and personalization data string authorizationFilter = webPart.AuthorizationFilter; // webPart.ID will be null for imported WebParts. Also, a user may want to call // this method on a WebPart before it has an ID. string webPartID = webPart.ID; if (!String.IsNullOrEmpty(webPartID) && Personalization.IsEnabled) { string personalizedAuthorizationFilter = Personalization.GetAuthorizationFilter(webPart.ID); if (personalizedAuthorizationFilter != null) { authorizationFilter = personalizedAuthorizationFilter; } } GenericWebPart genericWebPart = webPart as GenericWebPart; if (genericWebPart != null) { Type childType = null; string childPath = null; Control childControl = genericWebPart.ChildControl; UserControl childUserControl = childControl as UserControl; if (childUserControl != null) { childType = typeof(UserControl); childPath = childUserControl.AppRelativeVirtualPath; } else { childType = childControl.GetType(); } // Only authorize the type/path of the child control // Don't need to authorize the GenericWebPart as well return IsAuthorized(childType, childPath, authorizationFilter, webPart.IsShared); } else { return IsAuthorized(webPart.GetType(), null, authorizationFilter, webPart.IsShared); } } internal bool IsConsumerConnected(WebPart consumer, ConsumerConnectionPoint connectionPoint) { return (GetConnectionForConsumer(consumer, connectionPoint) != null); } internal bool IsProviderConnected(WebPart provider, ProviderConnectionPoint connectionPoint) { return (GetConnectionForProvider(provider, connectionPoint) != null); } /// /// Loads the control state for those properties that should persist across postbacks /// even when EnableViewState=false. /// protected internal override void LoadControlState(object savedState) { if (savedState == null) { base.LoadControlState(null); } else { object[] myState = (object[])savedState; if (myState.Length != controlStateArrayLength) { throw new ArgumentException(SR.GetString(SR.Invalid_ControlState)); } base.LoadControlState(myState[baseIndex]); // if (myState[selectedWebPartIndex] != null) { // All dynamic parts must be loaded before this point, in case a dynamic part is the // SelectedWebPart. WebPart selectedWebPart = WebParts[(string)myState[selectedWebPartIndex]]; if (selectedWebPart == null || selectedWebPart.IsClosed) { // The SelectedWebPart was either closed or deleted between requests. // Raise the changed event, since the SelectedWebPart was not null on the previous request. SetSelectedWebPart(null); OnSelectedWebPartChanged(new WebPartEventArgs(null)); } else { SetSelectedWebPart(selectedWebPart); } } if (myState[displayModeIndex] != null) { string modeName = (string)myState[displayModeIndex]; WebPartDisplayMode restoredDisplayMode = SupportedDisplayModes[modeName]; if (!restoredDisplayMode.IsEnabled(this)) { // Throw } if (restoredDisplayMode == null) { _displayMode = BrowseDisplayMode; OnDisplayModeChanged(new WebPartDisplayModeEventArgs(null)); } else { _displayMode = restoredDisplayMode; } } } } protected virtual void LoadCustomPersonalizationState(PersonalizationDictionary state) { // The state must be loaded after the Static Connections and WebParts have been added // to the WebPartManager (after the WebPartZone's and ProxyWebPartManager's Init methods) _personalizationState = state; } private void LoadDynamicConnections(PersonalizationEntry entry) { if (entry != null) { object[] dynamicConnectionState = (object[])entry.Value; if (dynamicConnectionState != null) { Debug.Assert(dynamicConnectionState.Length % 7 == 0); for (int i = 0; i < dynamicConnectionState.Length; i += 7) { string ID = (string)dynamicConnectionState[i]; string consumerID = (string)dynamicConnectionState[i + 1]; string consumerConnectionPointID = (string)dynamicConnectionState[i + 2]; string providerID = (string)dynamicConnectionState[i + 3]; string providerConnectionPointID = (string)dynamicConnectionState[i + 4]; // Add a new connection to the collection WebPartConnection connection = new WebPartConnection(); connection.ID = ID; connection.ConsumerID = consumerID; connection.ConsumerConnectionPointID = consumerConnectionPointID; connection.ProviderID = providerID; connection.ProviderConnectionPointID = providerConnectionPointID; Internals.SetIsShared(connection, (entry.Scope == PersonalizationScope.Shared)); Internals.SetIsStatic(connection, false); Type type = dynamicConnectionState[i + 5] as Type; if (type != null) { // SECURITY: Only instantiate type if it is a subclass of WebPartTransformer if (type.IsSubclassOf(typeof(WebPartTransformer))) { object configuration = dynamicConnectionState[i + 6]; WebPartTransformer transformer = (WebPartTransformer)Internals.CreateObjectFromType(type); Internals.LoadConfigurationState(transformer, configuration); Internals.SetTransformer(connection, transformer); } else { throw new InvalidOperationException(SR.GetString( SR.WebPartTransformerAttribute_NotTransformer, type.Name)); } } DynamicConnections.Add(connection); } } } } private void LoadDynamicWebPart(string id, string typeName, string path, string genericWebPartID, bool isShared) { WebPart dynamicWebPart = null; Type type = WebPartUtil.DeserializeType(typeName, false); if (type == null) { string errorMessage; if (Context != null && Context.IsCustomErrorEnabled) { errorMessage = SR.GetString(SR.WebPartManager_ErrorLoadingWebPartType); } else { errorMessage = SR.GetString(SR.Invalid_type, typeName); } dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage); } else if (type.IsSubclassOf(typeof(WebPart))) { string authorizationFilter = Personalization.GetAuthorizationFilter(id); if (IsAuthorized(type, null, authorizationFilter, isShared)) { try { dynamicWebPart = (WebPart)Internals.CreateObjectFromType(type); dynamicWebPart.ID = id; } catch { // If custom errors are enabled, we do not want to render the type name to the browser. // (VSWhidbey 381646) string errorMessage; if (Context != null && Context.IsCustomErrorEnabled) { errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstance); } else { errorMessage = SR.GetString( SR.WebPartManager_CantCreateInstanceWithType, typeName); } dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage); } } else { dynamicWebPart = new UnauthorizedWebPart(id, typeName, path, genericWebPartID); } } else if (type.IsSubclassOf(typeof(Control))) { string authorizationFilter = Personalization.GetAuthorizationFilter(genericWebPartID); if (IsAuthorized(type, path, authorizationFilter, isShared)) { Control childControl = null; try { if (!String.IsNullOrEmpty(path)) { Debug.Assert(type == typeof(UserControl)); childControl = Page.LoadControl(path); } else { childControl = (Control)Internals.CreateObjectFromType(type); } childControl.ID = id; dynamicWebPart = CreateWebPart(childControl); dynamicWebPart.ID = genericWebPartID; } catch { string errorMessage; if (childControl == null && String.IsNullOrEmpty(path)) { if (Context != null && Context.IsCustomErrorEnabled) { errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstance); } else { errorMessage = SR.GetString( SR.WebPartManager_CantCreateInstanceWithType, typeName); } } else if (childControl == null) { if (Context != null && Context.IsCustomErrorEnabled) { errorMessage = SR.GetString(SR.WebPartManager_InvalidPath); } else { errorMessage = SR.GetString( SR.WebPartManager_InvalidPathWithPath, path); } } else { errorMessage = SR.GetString(SR.WebPartManager_CantCreateGeneric); } dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage); } } else { dynamicWebPart = new UnauthorizedWebPart(id, typeName, path, genericWebPartID); } } else { // Type is not a subclass of Control. For security, do not even instantiate // the type (VSWhidbey 428511). string errorMessage; if (Context != null && Context.IsCustomErrorEnabled) { errorMessage = SR.GetString(SR.WebPartManager_TypeMustDeriveFromControl); } else { errorMessage = SR.GetString(SR.WebPartManager_TypeMustDeriveFromControlWithType, typeName); } dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage); } Debug.Assert(dynamicWebPart != null); Internals.SetIsStatic(dynamicWebPart, false); Internals.SetIsShared(dynamicWebPart, isShared); Internals.AddWebPart(dynamicWebPart); } private void LoadDynamicWebParts(PersonalizationEntry entry) { if (entry != null) { object[] dynamicWebPartState = (object[])entry.Value; if (dynamicWebPartState != null) { Debug.Assert(dynamicWebPartState.Length % 4 == 0); bool isShared = (entry.Scope == PersonalizationScope.Shared); // for (int i = 0; i < dynamicWebPartState.Length; i += 4) { string id = (string)dynamicWebPartState[i]; string typeName = (string)dynamicWebPartState[i + 1]; string path = (string)dynamicWebPartState[i + 2]; string genericWebPartID = (string)dynamicWebPartState[i + 3]; LoadDynamicWebPart(id, typeName, path, genericWebPartID, isShared); } } } } private void LoadDeletedConnectionState(PersonalizationEntry entry) { if (entry != null) { string[] deletedConnections = (string[])entry.Value; if (deletedConnections != null) { for (int i=0; i < deletedConnections.Length; i++) { string idToDelete = deletedConnections[i]; WebPartConnection connectionToDelete = null; foreach (WebPartConnection connection in StaticConnections) { if (String.Equals(connection.ID, idToDelete, StringComparison.OrdinalIgnoreCase)) { connectionToDelete = connection; break; } } if (connectionToDelete == null) { foreach (WebPartConnection connection in DynamicConnections) { if (String.Equals(connection.ID, idToDelete, StringComparison.OrdinalIgnoreCase)) { connectionToDelete = connection; break; } } } if (connectionToDelete != null) { // Only shared connections can be deleted Debug.Assert(connectionToDelete.IsShared); // In shared scope, only static connections should be deleted // In user scope, static and dynamic connections can be deleted Debug.Assert(connectionToDelete.IsStatic || entry.Scope == PersonalizationScope.User); Internals.DeleteConnection(connectionToDelete); } else { // Some of the personalization data is invalid, so we should mark ourselves // as dirty so the data will be re-saved, and the invalid data will be removed. _hasDataChanged = true; } } } } } /// /// Sets the ZoneID, ZoneIndex, and IsClosed properties on the WebParts. The state /// was loaded from personalization. /// private void LoadWebPartState(PersonalizationEntry entry) { if (entry != null) { object[] webPartState = (object[])entry.Value; if (webPartState != null) { Debug.Assert(webPartState.Length % 4 == 0); for (int i=0; i < webPartState.Length; i += 4) { string id = (string)webPartState[i]; string zoneID = (string)webPartState[i + 1]; int zoneIndex = (int)webPartState[i + 2]; bool isClosed = (bool)webPartState[i + 3]; WebPart part = (WebPart)FindControl(id); if (part != null) { Internals.SetZoneID(part, zoneID); Internals.SetZoneIndex(part, zoneIndex); // Internals.SetIsClosed(part, isClosed); } else { // Some of the personalization data is invalid, so we should mark ourselves // as dirty so the data will be re-saved, and the invalid data will be removed. _hasDataChanged = true; } } } } } /// /// public virtual void MoveWebPart(WebPart webPart, WebPartZoneBase zone, int zoneIndex) { Personalization.EnsureEnabled(/* ensureModifiable */ true); if (webPart == null) { throw new ArgumentNullException("webPart"); } if (!Controls.Contains(webPart)) { throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart"); } if (zone == null) { throw new ArgumentNullException("zone"); } if (_webPartZones.Contains(zone) == false) { throw new ArgumentException(SR.GetString(SR.WebPartManager_MustRegister), "zone"); } if (zoneIndex < 0) { throw new ArgumentOutOfRangeException("zoneIndex"); } if (webPart.Zone == null || webPart.IsClosed) { throw new ArgumentException(SR.GetString(SR.WebPartManager_MustBeInZone), "webPart"); } // Return immediately if moving part to its current location if ((webPart.Zone == zone) && (webPart.ZoneIndex == zoneIndex)) { return; } WebPartMovingEventArgs e = new WebPartMovingEventArgs(webPart, zone, zoneIndex); OnWebPartMoving(e); if (_allowEventCancellation && e.Cancel) { return; } RemoveWebPartFromZone(webPart); AddWebPartToZone(webPart, zone, zoneIndex); // Raise event at very end of Move method OnWebPartMoved(new WebPartEventArgs(webPart)); #if DEBUG CheckPartZoneIndexes(webPart.Zone); CheckPartZoneIndexes(zone); #endif } protected virtual void OnAuthorizeWebPart(WebPartAuthorizationEventArgs e) { WebPartAuthorizationEventHandler handler = (WebPartAuthorizationEventHandler)Events[AuthorizeWebPartEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnConnectionsActivated(EventArgs e) { EventHandler handler = (EventHandler)Events[ConnectionsActivatedEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnConnectionsActivating(EventArgs e) { EventHandler handler = (EventHandler)Events[ConnectionsActivatingEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnDisplayModeChanged(WebPartDisplayModeEventArgs e) { WebPartDisplayModeEventHandler handler = (WebPartDisplayModeEventHandler)Events[DisplayModeChangedEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnDisplayModeChanging(WebPartDisplayModeCancelEventArgs e) { WebPartDisplayModeCancelEventHandler handler = (WebPartDisplayModeCancelEventHandler)Events[DisplayModeChangingEvent]; if (handler != null) { handler(this, e); } } /// /// protected internal override void OnInit(EventArgs e) { base.OnInit(e); if (!DesignMode) { Page page = Page; if (page != null) { WebPartManager existingInstance = (WebPartManager)page.Items[typeof(WebPartManager)]; if (existingInstance != null) { Debug.Assert(existingInstance != this); throw new InvalidOperationException(SR.GetString(SR.WebPartManager_OnlyOneInstance)); } page.Items[typeof(WebPartManager)] = this; page.InitComplete += new EventHandler(this.OnPageInitComplete); page.LoadComplete += new EventHandler(this.OnPageLoadComplete); page.SaveStateComplete += new EventHandler(this.OnPageSaveStateComplete); page.RegisterRequiresControlState(this); Personalization.LoadInternal(); } } } /// /// protected internal override void OnUnload(EventArgs e) { base.OnUnload(e); if (!DesignMode) { Page page = Page; Debug.Assert(page != null); if (page != null) { page.Items.Remove(typeof(WebPartManager)); } } } private void OnPageInitComplete(object sender, EventArgs e) { if (_personalizationState != null) { // These must be loaded after the Static Connections have been added to the WebPartManager // (after the ProxyWebPartManager's Init methods) LoadDynamicConnections(_personalizationState["DynamicConnectionsShared"]); LoadDynamicConnections(_personalizationState["DynamicConnectionsUser"]); LoadDeletedConnectionState(_personalizationState["DeletedConnectionsShared"]); LoadDeletedConnectionState(_personalizationState["DeletedConnectionsUser"]); // These must be loaded after the Static WebParts have been added to the WebPartManager // (after the WebPartZone's Init methods) LoadDynamicWebParts(_personalizationState["DynamicWebPartsShared"]); LoadDynamicWebParts(_personalizationState["DynamicWebPartsUser"]); LoadWebPartState(_personalizationState["WebPartStateShared"]); LoadWebPartState(_personalizationState["WebPartStateUser"]); } _pageInitComplete = true; } private void OnPageLoadComplete(object sender, EventArgs e) { // VSWhidbey 77708 CloseOrphanedParts(); _allowCreateDisplayTitles = true; // Raise events outside of ActivateConnections() method, since the method is virtual OnConnectionsActivating(EventArgs.Empty); // Activate connections in Page.LoadComplete instead of WebPartManager.PreRender. // Additional connection types can be activated here, so this improves our compatibility. (VSWhidbey 266995) ActivateConnections(); OnConnectionsActivated(EventArgs.Empty); } private void OnPageSaveStateComplete(object sender, EventArgs e) { // NOTE: Ideally this would be done by overriding SaveViewState in // WebPartManager and WebPart to be symmetric with Personalization // loading which happens in TrackViewState. // However SaveViewState is not called when view state is disabled. Also, // we don't want to have everything register for the SaveStateComplete event, // because that creates more management issues for the event handler list. // We don't want to change how the Apply works either, because we'd have // to set up listeners for the Init event on every webpart. Personalization.ExtractPersonalizationState(); foreach (WebPart webPart in Controls) { Personalization.ExtractPersonalizationState(webPart); } Personalization.SaveInternal(); } protected internal override void OnPreRender(EventArgs e) { base.OnPreRender(e); if (Page != null) { Page.ClientScript.RegisterStartupScript( this, typeof(WebPartManager), ExportSensitiveDataWarningDeclaration, "var __wpmExportWarning='" + Util.QuoteJScriptString(ExportSensitiveDataWarning) + "';", true); Page.ClientScript.RegisterStartupScript( this, typeof(WebPartManager), CloseProviderWarningDeclaration, "var __wpmCloseProviderWarning='" + Util.QuoteJScriptString(CloseProviderWarning) + "';", true); Page.ClientScript.RegisterStartupScript( this, typeof(WebPartManager), DeleteWarningDeclaration, "var __wpmDeleteWarning='" + Util.QuoteJScriptString(DeleteWarning) + "';", true); _renderClientScript = CheckRenderClientScript(); if (_renderClientScript) { // Page.RegisterPostBackScript(); RegisterClientScript(); } } } protected virtual void OnSelectedWebPartChanged(WebPartEventArgs e) { WebPartEventHandler handler = (WebPartEventHandler)Events[SelectedWebPartChangedEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnSelectedWebPartChanging(WebPartCancelEventArgs e) { WebPartCancelEventHandler handler = (WebPartCancelEventHandler)Events[SelectedWebPartChangingEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnWebPartAdded(WebPartEventArgs e) { WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartAddedEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnWebPartAdding(WebPartAddingEventArgs e) { WebPartAddingEventHandler handler = (WebPartAddingEventHandler)Events[WebPartAddingEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnWebPartClosed(WebPartEventArgs e) { WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartClosedEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnWebPartClosing(WebPartCancelEventArgs e) { WebPartCancelEventHandler handler = (WebPartCancelEventHandler)Events[WebPartClosingEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnWebPartDeleted(WebPartEventArgs e) { WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartDeletedEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnWebPartDeleting(WebPartCancelEventArgs e) { WebPartCancelEventHandler handler = (WebPartCancelEventHandler)Events[WebPartDeletingEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnWebPartMoved(WebPartEventArgs e) { WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartMovedEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnWebPartMoving(WebPartMovingEventArgs e) { WebPartMovingEventHandler handler = (WebPartMovingEventHandler)Events[WebPartMovingEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnWebPartsConnected(WebPartConnectionsEventArgs e) { WebPartConnectionsEventHandler handler = (WebPartConnectionsEventHandler)Events[WebPartsConnectedEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnWebPartsConnecting(WebPartConnectionsCancelEventArgs e) { WebPartConnectionsCancelEventHandler handler = (WebPartConnectionsCancelEventHandler)Events[WebPartsConnectingEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnWebPartsDisconnected(WebPartConnectionsEventArgs e) { WebPartConnectionsEventHandler handler = (WebPartConnectionsEventHandler)Events[WebPartsDisconnectedEvent]; if (handler != null) { handler(this, e); } } protected virtual void OnWebPartsDisconnecting(WebPartConnectionsCancelEventArgs e) { WebPartConnectionsCancelEventHandler handler = (WebPartConnectionsCancelEventHandler)Events[WebPartsDisconnectingEvent]; if (handler != null) { handler(this, e); } } protected virtual void RegisterClientScript() { Page.ClientScript.RegisterClientScriptResource(this, typeof(WebPartManager), "WebParts.js"); bool allowPageDesign = DisplayMode.AllowPageDesign; string dragOverlayElementReference = "null"; if (allowPageDesign) { dragOverlayElementReference = "document.getElementById('" + ClientID + "___Drag')"; } StringBuilder zoneCode = new StringBuilder(1024); foreach (WebPartZoneBase zone in _webPartZones) { string isVertical = (zone.LayoutOrientation == Orientation.Vertical) ? "true" : "false"; string allowLayoutChange = "false"; string dragHighlightColor = "black"; if (allowPageDesign && zone.AllowLayoutChange) { allowLayoutChange = "true"; dragHighlightColor = ColorTranslator.ToHtml(zone.DragHighlightColor); } zoneCode.AppendFormat(ZoneScript, zone.ClientID, zone.UniqueID, isVertical, allowLayoutChange, dragHighlightColor); WebPartCollection webParts = GetWebPartsForZone(zone); foreach (WebPart webPart in webParts) { string titleBarElementReference = "null"; string allowMove = "false"; if (allowPageDesign) { titleBarElementReference = "document.getElementById('" + webPart.TitleBarID + "')"; if (webPart.AllowZoneChange) { allowMove = "true"; } } zoneCode.AppendFormat(ZonePartScript, webPart.WholePartID, titleBarElementReference, allowMove); } zoneCode.Append(ZoneEndScript); } string startupScript = String.Format(CultureInfo.InvariantCulture, StartupScript, dragOverlayElementReference, (Personalization.Scope == PersonalizationScope.Shared ? "true" : "false"), zoneCode.ToString()); Page.ClientScript.RegisterStartupScript(this, typeof(WebPartManager), String.Empty, startupScript, false); IScriptManager scriptManager = Page.ScriptManager; if ((scriptManager != null) && scriptManager.SupportsPartialRendering) { scriptManager.RegisterDispose(this, "WebPartManager_Dispose();"); } } internal void RegisterZone(WebZone zone) { Debug.Assert(zone != null); if (_pageInitComplete) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_RegisterTooLate)); } string zoneID = zone.ID; if (String.IsNullOrEmpty(zoneID)) { throw new ArgumentException(SR.GetString(SR.WebPartManager_NoZoneID), "zone"); } if (_zoneIDs.Contains(zoneID)) { throw new ArgumentException(SR.GetString(SR.WebPartManager_DuplicateZoneID, zoneID)); } _zoneIDs.Add(zoneID, zone); WebPartZoneBase webPartZone = zone as WebPartZoneBase; if (webPartZone != null) { if (_webPartZones.Contains(webPartZone)) { throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyRegistered), "zone"); } _webPartZones.Add(webPartZone); WebPartCollection initialWebParts = webPartZone.GetInitialWebParts(); ((WebPartManagerControlCollection)Controls).AddWebPartsFromZone(webPartZone, initialWebParts); } else { Debug.Assert(zone is ToolZone); ToolZone toolZone = (ToolZone)zone; WebPartDisplayModeCollection allDisplayModes = DisplayModes; WebPartDisplayModeCollection supportedDisplayModes = SupportedDisplayModes; foreach (WebPartDisplayMode displayMode in toolZone.AssociatedDisplayModes) { if (allDisplayModes.Contains(displayMode) && !supportedDisplayModes.Contains(displayMode)) { supportedDisplayModes.AddInternal(displayMode); } } } } /// /// Deletes the part from the dictionary mapping zones to parts. /// private void RemoveWebPartFromDictionary(WebPart webPart) { if (_partsForZone != null) { string zoneID = Internals.GetZoneID(webPart); if (!String.IsNullOrEmpty(zoneID)) { SortedList partsForZone = (SortedList)(_partsForZone[zoneID]); if (partsForZone != null) { partsForZone.Remove(webPart); } } } } // Called by WebPartManagerInternals internal void RemoveWebPart(WebPart webPart) { ((WebPartManagerControlCollection)Controls).RemoveWebPart(webPart); } /// /// Removes a web part from its zone, and renumbers all the remaining parts sequentially. /// private void RemoveWebPartFromZone(WebPart webPart) { Debug.Assert(!webPart.IsClosed); WebPartZoneBase zone = webPart.Zone; Internals.SetIsClosed(webPart, true); _hasDataChanged = true; RemoveWebPartFromDictionary(webPart); // if (zone != null) { IList parts = GetAllWebPartsForZone(zone); for (int i = 0; i < parts.Count; i++) { WebPart part = ((WebPart)parts[i]); Internals.SetZoneIndex(part, i); } } } protected internal override void Render(HtmlTextWriter writer) { if (DisplayMode.AllowPageDesign) { string dragOverlayElementHtml = String.Format(CultureInfo.InvariantCulture, DragOverlayElementHtmlTemplate, ClientID); writer.WriteLine(dragOverlayElementHtml); } } /// /// Saves the control state for those properties that should persist across postbacks /// even when EnableViewState=false. /// protected internal override object SaveControlState() { object[] myState = new object[controlStateArrayLength]; myState[baseIndex] = base.SaveControlState(); if (SelectedWebPart != null) { myState[selectedWebPartIndex] = SelectedWebPart.ID; } if (_displayMode != BrowseDisplayMode) { myState[displayModeIndex] = _displayMode.Name; } for (int i=0; i < controlStateArrayLength; i++) { if (myState[i] != null) { return myState; } } // More performant to return null than an array of null values return null; } protected virtual void SaveCustomPersonalizationState(PersonalizationDictionary state) { PersonalizationScope scope = Personalization.Scope; int webPartsCount = Controls.Count; if (webPartsCount > 0) { object[] webPartState = new object[webPartsCount * 4]; for (int i=0; i < webPartsCount; i++) { WebPart webPart = (WebPart)Controls[i]; webPartState[4*i] = webPart.ID; webPartState[4*i + 1] = Internals.GetZoneID(webPart); webPartState[4*i + 2] = webPart.ZoneIndex; webPartState[4*i + 3] = webPart.IsClosed; } if (scope == PersonalizationScope.Shared) { state["WebPartStateShared"] = new PersonalizationEntry(webPartState, PersonalizationScope.Shared); } else { state["WebPartStateUser"] = new PersonalizationEntry(webPartState, PersonalizationScope.User); } } // Select only the dynamic WebParts that should be saved for this mode ArrayList dynamicWebParts = new ArrayList(); foreach (WebPart webPart in Controls) { if (!webPart.IsStatic && ((scope == PersonalizationScope.User && !webPart.IsShared) || (scope == PersonalizationScope.Shared && webPart.IsShared))) { dynamicWebParts.Add(webPart); } } int dynamicWebPartsCount = dynamicWebParts.Count; if (dynamicWebPartsCount > 0) { // Use a 1-dimensional array for smallest storage space object[] dynamicWebPartState = new object[dynamicWebPartsCount * 4]; for (int i = 0; i < dynamicWebPartsCount; i++) { WebPart webPart = (WebPart)dynamicWebParts[i]; string id; string typeName; string path = null; string genericWebPartID = null; ProxyWebPart proxyWebPart = webPart as ProxyWebPart; if (proxyWebPart != null) { id = proxyWebPart.OriginalID; typeName = proxyWebPart.OriginalTypeName; path = proxyWebPart.OriginalPath; genericWebPartID = proxyWebPart.GenericWebPartID; } else { GenericWebPart genericWebPart = webPart as GenericWebPart; if (genericWebPart != null) { Control childControl = genericWebPart.ChildControl; UserControl userControl = childControl as UserControl; id = childControl.ID; if (userControl != null) { typeName = WebPartUtil.SerializeType(typeof(UserControl)); path = userControl.AppRelativeVirtualPath; } else { typeName = WebPartUtil.SerializeType(childControl.GetType()); } genericWebPartID = genericWebPart.ID; } else { id = webPart.ID; typeName = WebPartUtil.SerializeType(webPart.GetType()); } } dynamicWebPartState[4*i] = id; dynamicWebPartState[4*i + 1] = typeName; if (!String.IsNullOrEmpty(path)) { dynamicWebPartState[4*i + 2] = path; } if (!String.IsNullOrEmpty(genericWebPartID)) { dynamicWebPartState[4*i + 3] = genericWebPartID; } } if (scope == PersonalizationScope.Shared) { state["DynamicWebPartsShared"] = new PersonalizationEntry(dynamicWebPartState, PersonalizationScope.Shared); } else { state["DynamicWebPartsUser"] = new PersonalizationEntry(dynamicWebPartState, PersonalizationScope.User); } } // Save deleted connections // ArrayList deletedConnections = new ArrayList(); // PERF: Use the StaticConnections and DynamicConnections collections separately, instead // of using the Connections property which is created on every call. foreach (WebPartConnection connection in StaticConnections) { if (Internals.ConnectionDeleted(connection)) { deletedConnections.Add(connection); } } foreach (WebPartConnection connection in DynamicConnections) { if (Internals.ConnectionDeleted(connection)) { deletedConnections.Add(connection); } } int deletedConnectionsCount = deletedConnections.Count; if (deletedConnections.Count > 0) { string[] deletedConnectionsState = new string[deletedConnectionsCount]; for (int i=0; i < deletedConnectionsCount; i++) { WebPartConnection deletedConnection = (WebPartConnection)deletedConnections[i]; // Only shared connections can be deleted Debug.Assert(deletedConnection.IsShared); // In shared scope, only static connections should be deleted // In user scope, static and dynamic connections can be deleted Debug.Assert(deletedConnection.IsStatic || scope == PersonalizationScope.User); deletedConnectionsState[i] = deletedConnection.ID; } if (scope == PersonalizationScope.Shared) { state["DeletedConnectionsShared"] = new PersonalizationEntry(deletedConnectionsState, PersonalizationScope.Shared); } else { state["DeletedConnectionsUser"] = new PersonalizationEntry(deletedConnectionsState, PersonalizationScope.User); } } // Select only the dynamic Connections that should be saved for this mode ArrayList dynamicConnections = new ArrayList(); foreach (WebPartConnection connection in DynamicConnections) { if (((scope == PersonalizationScope.User) && (!connection.IsShared)) || ((scope == PersonalizationScope.Shared) && (connection.IsShared))) { dynamicConnections.Add(connection); } } int dynamicConnectionsCount = dynamicConnections.Count; if (dynamicConnectionsCount > 0) { // Use a 1-dimensional array for smallest storage space object[] dynamicConnectionState = new object[dynamicConnectionsCount * 7]; for (int i = 0; i < dynamicConnectionsCount; i++) { WebPartConnection connection = (WebPartConnection)dynamicConnections[i]; WebPartTransformer transformer = connection.Transformer; // We should never be saving a deleted dynamic connection. If the User has deleted a // a shared connection, the connection will be saved in the Shared data, not here. Debug.Assert(!Internals.ConnectionDeleted(connection)); dynamicConnectionState[7*i] = connection.ID; dynamicConnectionState[7*i + 1] = connection.ConsumerID; dynamicConnectionState[7*i + 2] = connection.ConsumerConnectionPointID; dynamicConnectionState[7*i + 3] = connection.ProviderID; dynamicConnectionState[7*i + 4] = connection.ProviderConnectionPointID; if (transformer != null) { dynamicConnectionState[7*i + 5] = transformer.GetType(); dynamicConnectionState[7*i + 6] = Internals.SaveConfigurationState(transformer); } } if (scope == PersonalizationScope.Shared) { state["DynamicConnectionsShared"] = new PersonalizationEntry(dynamicConnectionState, PersonalizationScope.Shared); } else { state["DynamicConnectionsUser"] = new PersonalizationEntry(dynamicConnectionState, PersonalizationScope.User); } } } // Can be called by a derived WebPartManager to mark itself as dirty protected void SetPersonalizationDirty() { Personalization.SetDirty(); } // Returns true if the WebPart should currently be rendered in the Zone. Determines // which WebParts are returned by GetWebPartsForZone. private bool ShouldRenderWebPartInZone(WebPart part, WebPartZoneBase zone) { Debug.Assert(part.Zone == zone); // Never render UnauthorizedWebParts if (part is UnauthorizedWebPart) { return false; } return true; } protected void SetSelectedWebPart(WebPart webPart) { _selectedWebPart = webPart; } // PropertyInfo will be null for an IPersonalizable property, since there is no associated PropertyInfo private bool ShouldExportProperty(PropertyInfo propertyInfo, Type propertyValueType, object propertyValue, out string exportString) { string propertyValueAsString = propertyValue as string; if (propertyValueAsString != null) { exportString = propertyValueAsString; return true; } else { TypeConverter converter = null; if (propertyInfo != null) { // See if the property itself has a type converter associated with it TypeConverterAttribute attr = Attribute.GetCustomAttribute(propertyInfo, typeof(TypeConverterAttribute), true) as TypeConverterAttribute; if (attr != null) { // Get the type using DeserializeType(), which calls BuildManager.GetType(), // since we want this to work with a non-assembly qualified typename // in the Code directory. Type converterType = WebPartUtil.DeserializeType(attr.ConverterTypeName, false); // SECURITY: Check that the type is a subclass of TypeConverter before instantiating. if (converterType != null && converterType.IsSubclassOf(typeof(TypeConverter))) { TypeConverter tempConverter = (TypeConverter)(Internals.CreateObjectFromType(converterType)); if (Util.CanConvertToFrom(tempConverter, typeof(string))) { converter = tempConverter; } } } } if (converter == null) { // If there was no valid type converter on the property info, look on the type of the value TypeConverter tempConverter = TypeDescriptor.GetConverter(propertyValueType); if (Util.CanConvertToFrom(tempConverter, typeof(string))) { converter = tempConverter; } } // Only export property if we found a valid type converter (VSWhidbey 496495) if (converter != null) { if (propertyValue != null) { exportString = converter.ConvertToInvariantString(propertyValue); return true; } else { // Special-case null value exportString = null; return true; } } else { exportString = null; if (propertyInfo == null && propertyValue == null) { // Always want to export a null IPersonalizable value, since we will never have a type // converter for the value. However, we should not export a null Personalizable value // unless the propertyInfo had a type converter, since we may not be able to import a // null value, since the property may be a value type that cannot accept null as a value. // (VSWhidbey 537895) return true; } else { return false; } } } } /// /// Returns true if the connection should be removed from the dynamic connection /// collection when deleted. /// private bool ShouldRemoveConnection(WebPartConnection connection) { Debug.Assert(Personalization.IsModifiable); if (connection.IsShared && (Personalization.Scope == PersonalizationScope.User)) { // Can't remove shared connection in user mode return false; } else { return true; } } /// protected override void TrackViewState() { Personalization.ApplyPersonalizationState(); base.TrackViewState(); } // Throw if the type cannot be loaded by BuildManager // For instance, we cannot load a type defined in the Page class private void VerifyType(Control control) { // Don't need to verify type of UserControls, since we load them using // their path instead of their type if (control is UserControl) { return; } Type type = control.GetType(); string typeName = WebPartUtil.SerializeType(type); Type loadedType = WebPartUtil.DeserializeType(typeName, /* throwOnError */ false); if (loadedType != type) { throw new InvalidOperationException( SR.GetString(SR.WebPartManager_CantAddControlType, typeName)); } } #region Implementation of IPersonalizable /// bool IPersonalizable.IsDirty { get { return IsCustomPersonalizationStateDirty; } } /// void IPersonalizable.Load(PersonalizationDictionary state) { LoadCustomPersonalizationState(state); } /// void IPersonalizable.Save(PersonalizationDictionary state) { SaveCustomPersonalizationState(state); } #endregion private sealed class WebPartManagerControlCollection : ControlCollection { private WebPartManager _manager; public WebPartManagerControlCollection(WebPartManager owner) : base(owner) { _manager = owner; SetCollectionReadOnly(SR.WebPartManager_CannotModify); } internal void AddWebPart(WebPart webPart) { string originalError = SetCollectionReadOnly(null); // Extra try-catch block to prevent elevation of privilege attack via exception filter try { try { AddWebPartHelper(webPart); } finally { SetCollectionReadOnly(originalError); } } catch { throw; } } private void AddWebPartHelper(WebPart webPart) { string partID = webPart.ID; if (String.IsNullOrEmpty(partID)) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoWebPartID)); } if (_manager._partAndChildControlIDs.Contains(partID)) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DuplicateWebPartID, partID)); } // Add to dictionary to prevent duplicate IDs, even if this part is not authorized. Don't want page // developer to have 2 parts with the same ID, and not get the exception until they are both authorized. _manager._partAndChildControlIDs.Add(partID, null); // Check and add child control ID (VSWhidbey 339482) GenericWebPart genericWebPart = webPart as GenericWebPart; if (genericWebPart != null) { string childControlID = genericWebPart.ChildControl.ID; if (String.IsNullOrEmpty(childControlID)) { throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoChildControlID)); } if (_manager._partAndChildControlIDs.Contains(childControlID)) { throw new InvalidOperationException(SR.GetString( SR.WebPartManager_DuplicateWebPartID, childControlID)); } _manager._partAndChildControlIDs.Add(childControlID, null); } _manager.Internals.SetIsStandalone(webPart, false); webPart.SetWebPartManager(_manager); Add(webPart); // Invalidate the part dictionary if it has already been created _manager._partsForZone = null; } internal void AddWebPartsFromZone(WebPartZoneBase zone, WebPartCollection webParts) { if ((webParts != null) && (webParts.Count != 0)) { string originalError = SetCollectionReadOnly(null); // Extra try-catch block to prevent elevation of privilege attack via exception filter try { try { string zoneID = zone.ID; int index = 0; foreach (WebPart webPart in webParts) { // Need to set IsShared before calling IsAuthorized _manager.Internals.SetIsShared(webPart, true); WebPart webPartOrProxy = webPart; if (!_manager.IsAuthorized(webPart)) { webPartOrProxy = new UnauthorizedWebPart(webPart); } _manager.Internals.SetIsStatic(webPartOrProxy, true); _manager.Internals.SetIsShared(webPartOrProxy, true); _manager.Internals.SetZoneID(webPartOrProxy, zoneID); _manager.Internals.SetZoneIndex(webPartOrProxy, index); AddWebPartHelper(webPartOrProxy); index++; } } finally { SetCollectionReadOnly(originalError); } } catch { throw; } } } internal void RemoveWebPart(WebPart webPart) { string originalError = SetCollectionReadOnly(null); // Extra try-catch block to prevent elevation of privilege attack via exception filter try { try { _manager._partAndChildControlIDs.Remove(webPart.ID); // Remove child control ID (VSWhidbey 339482) GenericWebPart genericWebPart = webPart as GenericWebPart; if (genericWebPart != null) { _manager._partAndChildControlIDs.Remove(genericWebPart.ChildControl.ID); } Remove(webPart); _manager._hasDataChanged = true; webPart.SetWebPartManager(null); _manager.Internals.SetIsStandalone(webPart, true); // Invalidate the part dictionary if it has already been created _manager._partsForZone = null; } finally { SetCollectionReadOnly(originalError); } } catch { throw; } } } private sealed class BrowseWebPartDisplayMode : WebPartDisplayMode { public BrowseWebPartDisplayMode() : base("Browse") { } } private sealed class CatalogWebPartDisplayMode : WebPartDisplayMode { public CatalogWebPartDisplayMode() : base("Catalog") { } public override bool AllowPageDesign { get { return true; } } public override bool AssociatedWithToolZone { get { return true; } } public override bool RequiresPersonalization { get { return true; } } public override bool ShowHiddenWebParts { get { return true; } } } private sealed class ConnectionPointKey { // DevDiv Bugs 38677 // used as the Cache key for Connection Points, using Type and Culture private Type _type; private CultureInfo _culture; private CultureInfo _uiCulture; public ConnectionPointKey(Type type, CultureInfo culture, CultureInfo uiCulture) { Debug.Assert(type != null && culture != null && uiCulture != null); _type = type; _culture = culture; _uiCulture = uiCulture; } public override bool Equals(object obj) { if (obj == this) { return true; } ConnectionPointKey other = obj as ConnectionPointKey; return (other != null) && (other._type.Equals(_type)) && (other._culture.Equals(_culture)) && (other._uiCulture.Equals(_uiCulture)); } public override int GetHashCode() { int typeHashCode = _type.GetHashCode(); // This is the algorithm used in Whidbey to combine hashcodes. // It adheres better than a simple XOR to the randomness requirement for hashcodes. int hashCode = ((typeHashCode << 5) + typeHashCode) ^ _culture.GetHashCode(); return ((hashCode << 5) + hashCode) ^ _uiCulture.GetHashCode(); } } private sealed class ConnectWebPartDisplayMode : WebPartDisplayMode { public ConnectWebPartDisplayMode() : base("Connect") { } public override bool AllowPageDesign { get { return true; } } public override bool AssociatedWithToolZone { get { return true; } } public override bool RequiresPersonalization { get { return true; } } public override bool ShowHiddenWebParts { get { return true; } } } private sealed class DesignWebPartDisplayMode : WebPartDisplayMode { public DesignWebPartDisplayMode() : base("Design") { } public override bool AllowPageDesign { get { return true; } } public override bool RequiresPersonalization { get { return true; } } public override bool ShowHiddenWebParts { get { return true; } } } private sealed class EditWebPartDisplayMode : WebPartDisplayMode { public EditWebPartDisplayMode() : base("Edit") { } public override bool AllowPageDesign { get { return true; } } public override bool AssociatedWithToolZone { get { return true; } } public override bool RequiresPersonalization { get { return true; } } public override bool ShowHiddenWebParts { get { return true; } } } } }

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK