1 //------------------------------------------------------------------------------
2 // <copyright file="WebPartManager.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
5 //------------------------------------------------------------------------------
7 namespace System.Web.UI.WebControls.WebParts {
10 using System.Collections;
11 using System.Collections.Specialized;
12 using System.ComponentModel;
13 using System.Diagnostics.CodeAnalysis;
15 using System.Globalization;
17 using System.Reflection;
18 using System.Security;
19 using System.Security.Permissions;
22 using System.Web.Configuration;
24 using System.Web.UI.WebControls;
25 using System.Web.Util;
30 Designer("System.Web.UI.Design.WebControls.WebParts.WebPartManagerDesigner, " + AssemblyRef.SystemDesign),
33 PersistChildren(false),
36 public class WebPartManager : Control, INamingContainer, IPersonalizable {
38 public static readonly WebPartDisplayMode CatalogDisplayMode = new CatalogWebPartDisplayMode();
39 public static readonly WebPartDisplayMode ConnectDisplayMode = new ConnectWebPartDisplayMode();
40 public static readonly WebPartDisplayMode DesignDisplayMode = new DesignWebPartDisplayMode();
41 public static readonly WebPartDisplayMode EditDisplayMode = new EditWebPartDisplayMode();
42 public static readonly WebPartDisplayMode BrowseDisplayMode = new BrowseWebPartDisplayMode();
44 // Cache collections of ConnectionPoints for each object Type. We store an array of
45 // 2 ConnectionPointCollections (consumer, provider) for each Type. The Hashtable
46 // is synchronized so it is threadsafe with multiple writers.
47 private static Hashtable ConnectionPointsCache;
49 private static readonly object AuthorizeWebPartEvent = new object();
50 private static readonly object ConnectionsActivatedEvent = new object();
51 private static readonly object ConnectionsActivatingEvent = new object();
52 private static readonly object DisplayModeChangedEvent = new object();
53 private static readonly object DisplayModeChangingEvent = new object();
54 private static readonly object SelectedWebPartChangingEvent = new object();
55 private static readonly object SelectedWebPartChangedEvent = new object();
56 private static readonly object WebPartAddedEvent = new object();
57 private static readonly object WebPartAddingEvent = new object();
58 private static readonly object WebPartClosedEvent = new object();
59 private static readonly object WebPartClosingEvent = new object();
60 private static readonly object WebPartDeletedEvent = new object();
61 private static readonly object WebPartDeletingEvent = new object();
62 private static readonly object WebPartMovedEvent = new object();
63 private static readonly object WebPartMovingEvent = new object();
64 private static readonly object WebPartsConnectedEvent = new object();
65 private static readonly object WebPartsConnectingEvent = new object();
66 private static readonly object WebPartsDisconnectedEvent = new object();
67 private static readonly object WebPartsDisconnectingEvent = new object();
69 private PermissionSet _minimalPermissionSet;
70 private PermissionSet _mediumPermissionSet;
71 private bool? _usePermitOnly;
73 private const string DynamicConnectionIDPrefix = "c";
74 private const string DynamicWebPartIDPrefix = "wp";
76 private const int baseIndex = 0;
77 private const int selectedWebPartIndex = 1;
78 private const int displayModeIndex = 2;
79 private const int controlStateArrayLength = 3;
81 private WebPartPersonalization _personalization;
82 private WebPartDisplayMode _displayMode;
83 private WebPartDisplayModeCollection _displayModes;
84 private WebPartDisplayModeCollection _supportedDisplayModes;
85 private WebPartManagerInternals _internals;
87 private bool _allowCreateDisplayTitles;
88 private bool _pageInitComplete;
90 // When this flag is set to false, then cancelled events are ignored. We will not actually
91 // cancel the action even though e.Cancel is true. (VSWhidbey 516012)
92 private bool _allowEventCancellation;
94 private PersonalizationDictionary _personalizationState;
95 private bool _hasDataChanged;
97 private WebPartConnectionCollection _staticConnections;
98 private WebPartConnectionCollection _dynamicConnections;
100 private WebPartZoneCollection _webPartZones;
101 private TransformerTypeCollection _availableTransformers;
103 // Dictionary mapping a WebPart to its DisplayTitle. Created and filled on demand when
104 // GetDisplayTitle() is called after PreRender.
105 private IDictionary _displayTitles;
107 // NOTE: We are no longer rendering the LRO or PDF characters (VSWhidbey 364897)
108 // LRO is the Unicode left-to-right override marker. Effectively creates a "run break"
109 // so that contents in parentheses et. al. maintain correct reading order regardless
110 // of text direction (LTR or RTL). PDF "pops" the formatting and allows ensuing text
111 // to lay out as it would w/o the markers. The PDF is needed when constructing dialogs
112 // that use the web part titles. We must use the Unicode characters instead of
113 // <span dir="ltr">, since the DisplayTitle is HTML Encoded before being rendered.
114 // (VSWhidbey 190501)
115 // private static string LRO = new String((char)0x202d, 1); // left-to-right override
116 // private static string PDF = new String((char)0x202c, 1); // pop directional formatting
118 // PERF: At compile-time, compute strings to append to DisplayTitle
119 // We chose to compute suffixes up to 20, since it is unlikely there will be more than
120 // 20 WebParts with the same title.
121 // The 0 element is currently not used, but is a placeholder so the index into the array
122 // matches the string.
123 private static string[] displayTitleSuffix = new string[] {
124 " [0]", " [1]", " [2]", " [3]", " [4]", " [5]", " [6]", " [7]", " [8]", " [9]", " [10]",
125 " [11]", " [12]", " [13]", " [14]", " [15]", " [16]", " [17]", " [18]", " [19]", " [20]" };
127 // Dictionary mapping a zone to the parts in the zone. Used by GetAllWebPartsForZone
128 // to improve performance.
129 private IDictionary _partsForZone;
131 // Contains the IDs of WebParts and Child Controls already added. WebParts and the child
132 // controls of GenericWebParts share the same namespace, meaning you cannot have a WebPart
133 // and a Child Control with the same ID. An exception is thrown if a WebPart or Child Control
134 // is added with a duplicate ID.
135 private IDictionary _partAndChildControlIDs;
137 // Contains the IDs of Zones already added. An exception is thrown if a Zone is added with
139 private IDictionary _zoneIDs;
141 private WebPart _selectedWebPart;
143 private bool _renderClientScript;
145 private const string DragOverlayElementHtmlTemplate = @"
146 <div id=""{0}___Drag"" style=""display:none; position:absolute; z-index: 32000; filter:alpha(opacity=75)""></div>";
147 private const string ExportSensitiveDataWarningDeclaration = "ExportSensitiveDataWarningDeclaration";
148 private const string CloseProviderWarningDeclaration = "CloseProviderWarningDeclaration";
149 private const string DeleteWarningDeclaration = "DeleteWarningDeclaration";
150 private const string StartupScript = @"
151 <script type=""text/javascript"">
153 __wpm = new WebPartManager();
154 __wpm.overlayContainerElement = {0};
155 __wpm.personalizationScopeShared = {1};
162 private const string ZoneScript = @"
163 zoneElement = document.getElementById('{0}');
164 if (zoneElement != null) {{
165 zoneObject = __wpm.AddZone(zoneElement, '{1}', {2}, {3}, '{4}');";
167 private const string ZonePartScript = @"
168 zoneObject.AddWebPart(document.getElementById('{0}'), {1}, {2});";
170 private const string ZoneEndScript = @"
173 private const string AuthorizationFilterName = "AuthorizationFilter";
174 private const string ImportErrorMessageName = "ImportErrorMessage";
175 private const string ZoneIDName = "ZoneID";
176 private const string ZoneIndexName = "ZoneIndex";
178 internal const string ExportRootElement = "webParts";
179 internal const string ExportPartElement = "webPart";
180 internal const string ExportPartNamespaceAttribute = "xmlns";
181 internal const string ExportPartNamespaceValue = "http://schemas.microsoft.com/WebPart/v3";
182 internal const string ExportMetaDataElement = "metaData";
183 internal const string ExportTypeElement = "type";
184 internal const string ExportErrorMessageElement = "importErrorMessage";
185 internal const string ExportDataElement = "data";
186 internal const string ExportPropertiesElement = "properties";
187 internal const string ExportPropertyElement = "property";
188 internal const string ExportTypeNameAttribute = "name";
189 internal const string ExportUserControlSrcAttribute = "src";
190 internal const string ExportPropertyNameAttribute = "name";
191 internal const string ExportGenericPartPropertiesElement = "genericWebPartProperties";
192 internal const string ExportIPersonalizableElement = "ipersonalizable";
193 internal const string ExportPropertyTypeAttribute = "type";
194 internal const string ExportPropertyScopeAttribute = "scope";
195 internal const string ExportPropertyNullAttribute = "null";
197 private const string ExportTypeBool = "bool";
198 private const string ExportTypeInt = "int";
199 private const string ExportTypeChromeState = "chromestate";
200 private const string ExportTypeChromeType = "chrometype";
201 private const string ExportTypeColor = "color";
202 private const string ExportTypeDateTime = "datetime";
203 private const string ExportTypeDirection = "direction";
204 private const string ExportTypeDouble = "double";
205 private const string ExportTypeExportMode = "exportmode";
206 private const string ExportTypeFontSize = "fontsize";
207 private const string ExportTypeHelpMode = "helpmode";
208 private const string ExportTypeObject = "object";
209 private const string ExportTypeSingle = "single";
210 private const string ExportTypeString = "string";
211 private const string ExportTypeUnit = "unit";
215 public WebPartManager() {
216 _allowEventCancellation = true;
217 _displayMode = BrowseDisplayMode;
218 _webPartZones = new WebPartZoneCollection();
219 _partAndChildControlIDs = new HybridDictionary(true /* caseInsensitive */);
220 _zoneIDs = new HybridDictionary(true /* caseInsensitive */);
225 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
227 public TransformerTypeCollection AvailableTransformers {
229 if (_availableTransformers == null) {
230 _availableTransformers = CreateAvailableTransformers();
232 return _availableTransformers;
237 WebCategory("Behavior"),
238 WebSysDefaultValue(SR.WebPartManager_DefaultCloseProviderWarning),
239 WebSysDescription(SR.WebPartManager_CloseProviderWarning)
241 public virtual string CloseProviderWarning {
243 object o = ViewState["CloseProviderWarning"];
244 return (o != null) ? (string)o : SR.GetString(SR.WebPartManager_DefaultCloseProviderWarning);
247 ViewState["CloseProviderWarning"] = value;
253 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
255 public WebPartConnectionCollection Connections {
257 WebPartConnectionCollection connections = new WebPartConnectionCollection(this);
258 if (_staticConnections != null) {
259 foreach (WebPartConnection connection in _staticConnections) {
260 if (!Internals.ConnectionDeleted(connection)) {
261 connections.Add(connection);
265 if (_dynamicConnections != null) {
266 foreach (WebPartConnection connection in _dynamicConnections) {
267 if (!Internals.ConnectionDeleted(connection)) {
268 connections.Add(connection);
272 connections.SetReadOnly(SR.WebPartManager_ConnectionsReadOnly);
277 // Hide the Controls property from IntelliSense. The developer should use the
278 // WebParts property instead.
280 EditorBrowsable(EditorBrowsableState.Never),
282 public override ControlCollection Controls {
284 return base.Controls;
289 WebCategory("Behavior"),
290 WebSysDefaultValue(SR.WebPartManager_DefaultDeleteWarning),
291 WebSysDescription(SR.WebPartManager_DeleteWarning)
293 public virtual string DeleteWarning {
295 object o = ViewState["DeleteWarning"];
296 return (o != null) ? (string)o : SR.GetString(SR.WebPartManager_DefaultDeleteWarning);
299 ViewState["DeleteWarning"] = value;
305 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
307 public virtual WebPartDisplayMode DisplayMode {
313 throw new ArgumentNullException("value");
316 if (DisplayMode == value) {
320 if (SupportedDisplayModes.Contains(value) == false) {
321 throw new ArgumentException(SR.GetString(SR.WebPartManager_InvalidDisplayMode), "value");
324 if (!value.IsEnabled(this)) {
325 throw new ArgumentException(SR.GetString(SR.WebPartManager_DisabledDisplayMode), "value");
328 WebPartDisplayModeCancelEventArgs dmce = new WebPartDisplayModeCancelEventArgs(value);
329 OnDisplayModeChanging(dmce);
331 if (_allowEventCancellation && dmce.Cancel) {
335 // Custom display modes can take actions like this in the OnDisplayModeChanging method.
337 // public override void OnDisplayModeChanging(WebPartDisplayModeCancelEventArgs e) {
338 // base.OnDisplayModeChanging(e);
339 // if (e.Cancel) return;
340 // if (DisplayMode == CustomDisplayMode) {
341 // // Take some actions and set e.Cancel=true if appropriate
345 // End web part connecting if necessary
346 if ((DisplayMode == ConnectDisplayMode) && (SelectedWebPart != null)) {
347 EndWebPartConnecting();
348 if (SelectedWebPart != null) {
349 // WebPartConnectModeChanging event was cancelled
354 // End web part editing if necessary
355 if ((DisplayMode == EditDisplayMode) && (SelectedWebPart != null)) {
357 if (SelectedWebPart != null) {
358 // WebPartEditModeChanging event was cancelled
363 WebPartDisplayModeEventArgs dme = new WebPartDisplayModeEventArgs(DisplayMode);
364 _displayMode = value;
365 OnDisplayModeChanged(dme);
371 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
373 public WebPartDisplayModeCollection DisplayModes {
375 if (_displayModes == null) {
376 _displayModes = CreateDisplayModes();
377 _displayModes.SetReadOnly(SR.WebPartManager_DisplayModesReadOnly);
380 return _displayModes;
384 protected internal WebPartConnectionCollection DynamicConnections {
386 if (_dynamicConnections == null) {
387 _dynamicConnections = new WebPartConnectionCollection(this);
389 return _dynamicConnections;
395 WebCategory("Behavior"),
396 WebSysDescription(SR.WebPartManager_EnableClientScript)
398 public virtual bool EnableClientScript {
400 object o = ViewState["EnableClientScript"];
401 return (o != null) ? (bool)o : true;
404 ViewState["EnableClientScript"] = value;
408 // Theming must be enabled, so the WebPart child controls have theming enabled
412 EditorBrowsable(EditorBrowsableState.Never),
414 public override bool EnableTheming {
419 throw new NotSupportedException(SR.GetString(SR.WebPartManager_CantSetEnableTheming));
424 WebCategory("Behavior"),
425 WebSysDefaultValue(SR.WebPartChrome_ConfirmExportSensitive),
426 WebSysDescription(SR.WebPartManager_ExportSensitiveDataWarning)
428 public virtual string ExportSensitiveDataWarning {
430 object o = ViewState["ExportSensitiveDataWarning"];
431 return (o != null) ? (string)o : SR.GetString(SR.WebPartChrome_ConfirmExportSensitive);
434 ViewState["ExportSensitiveDataWarning"] = value;
439 EditorBrowsable(EditorBrowsableState.Never),
441 protected WebPartManagerInternals Internals {
443 if (_internals == null) {
444 _internals = new WebPartManagerInternals(this);
452 protected virtual bool IsCustomPersonalizationStateDirty {
454 return _hasDataChanged;
458 // PermissionSet that allows only Execution and AspNetHostingPermissionLevel.Medium.
459 // AspNetHostingPermissionLevel.Medium is needed to call BuildManager.GetType().
460 // Used for during Import for type deserialization.
461 protected virtual PermissionSet MediumPermissionSet {
463 if (_mediumPermissionSet == null) {
464 _mediumPermissionSet = new PermissionSet(PermissionState.None);
465 _mediumPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
466 _mediumPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Medium));
468 return _mediumPermissionSet;
472 // PermissionSet that allows only Execution and AspNetHostingPermissionLevel.Minimal.
473 // Used for during Import for everything except type deserialization.
474 protected virtual PermissionSet MinimalPermissionSet {
476 if (_minimalPermissionSet == null) {
477 _minimalPermissionSet = new PermissionSet(PermissionState.None);
478 _minimalPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
479 _minimalPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Minimal));
481 return _minimalPermissionSet;
489 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
490 NotifyParentProperty(true),
491 PersistenceMode(PersistenceMode.InnerProperty),
492 WebCategory("Behavior"),
493 WebSysDescription(SR.WebPartManager_Personalization)
495 public WebPartPersonalization Personalization {
497 if (_personalization == null) {
498 _personalization = CreatePersonalization();
501 return _personalization;
505 internal bool RenderClientScript {
507 return _renderClientScript;
513 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
515 public WebPart SelectedWebPart {
517 return _selectedWebPart;
524 EditorBrowsable(EditorBrowsableState.Never),
526 public override string SkinID {
531 throw new NotSupportedException(SR.GetString(SR.NoThemingSupport, this.GetType().Name));
537 DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
538 MergableProperty(false),
539 PersistenceMode(PersistenceMode.InnerProperty),
540 WebCategory("Behavior"),
541 WebSysDescription(SR.WebPartManager_StaticConnections),
543 public WebPartConnectionCollection StaticConnections {
545 if (_staticConnections == null) {
546 _staticConnections = new WebPartConnectionCollection(this);
548 return _staticConnections;
554 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
556 public WebPartDisplayModeCollection SupportedDisplayModes {
558 if (_supportedDisplayModes == null) {
559 _supportedDisplayModes = new WebPartDisplayModeCollection();
561 foreach (WebPartDisplayMode mode in DisplayModes) {
562 if (mode.AssociatedWithToolZone == false) {
563 _supportedDisplayModes.Add(mode);
567 _supportedDisplayModes.SetReadOnly(SR.WebPartManager_DisplayModesReadOnly);
569 return _supportedDisplayModes;
573 // Only call PermitOnly() in legacy CAS mode. In the v4 CAS model, calling PermitOnly() would prevent us from calling
574 // Activator.CreateInstance() on types in App_Code (assuming it is non-APTCA). (Dev10 Bug 807117)
575 private bool UsePermitOnly {
577 if (!_usePermitOnly.HasValue) {
578 _usePermitOnly = RuntimeConfig.GetAppConfig().Trust.LegacyCasModel;
580 return _usePermitOnly.Value;
587 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
588 EditorBrowsable(EditorBrowsableState.Never),
590 public override bool Visible {
592 // Even though we are a non-visual control, this returns true, because we want our
593 // child controls (the WebParts) to be Visible.
597 throw new NotSupportedException(SR.GetString(SR.ControlNonVisual, this.GetType().Name));
602 /// All the WebParts on the page.
606 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
608 public WebPartCollection WebParts {
610 // PERF: Consider changing WebPartCollection so it just wraps the ControlCollection,
611 // instead of copying the controls to a new collection.
613 return new WebPartCollection(Controls);
616 return new WebPartCollection();
623 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
625 public WebPartZoneCollection Zones {
627 return _webPartZones;
632 WebCategory("Action"),
633 WebSysDescription(SR.WebPartManager_AuthorizeWebPart)
635 public event WebPartAuthorizationEventHandler AuthorizeWebPart {
637 Events.AddHandler(AuthorizeWebPartEvent, value);
640 Events.RemoveHandler(AuthorizeWebPartEvent, value);
645 WebCategory("Action"),
646 WebSysDescription(SR.WebPartManager_ConnectionsActivated)
648 public event EventHandler ConnectionsActivated {
650 Events.AddHandler(ConnectionsActivatedEvent, value);
653 Events.RemoveHandler(ConnectionsActivatedEvent, value);
658 WebCategory("Action"),
659 WebSysDescription(SR.WebPartManager_ConnectionsActivating)
661 public event EventHandler ConnectionsActivating {
663 Events.AddHandler(ConnectionsActivatingEvent, value);
666 Events.RemoveHandler(ConnectionsActivatingEvent, value);
671 WebCategory("Action"),
672 WebSysDescription(SR.WebPartManager_DisplayModeChanged)
674 public event WebPartDisplayModeEventHandler DisplayModeChanged {
676 Events.AddHandler(DisplayModeChangedEvent, value);
679 Events.RemoveHandler(DisplayModeChangedEvent, value);
684 WebCategory("Action"),
685 WebSysDescription(SR.WebPartManager_DisplayModeChanging)
687 public event WebPartDisplayModeCancelEventHandler DisplayModeChanging {
689 Events.AddHandler(DisplayModeChangingEvent, value);
692 Events.RemoveHandler(DisplayModeChangingEvent, value);
697 WebCategory("Action"),
698 WebSysDescription(SR.WebPartManager_SelectedWebPartChanged)
700 public event WebPartEventHandler SelectedWebPartChanged {
702 Events.AddHandler(SelectedWebPartChangedEvent, value);
705 Events.RemoveHandler(SelectedWebPartChangedEvent, value);
710 WebCategory("Action"),
711 WebSysDescription(SR.WebPartManager_SelectedWebPartChanging)
713 public event WebPartCancelEventHandler SelectedWebPartChanging {
715 Events.AddHandler(SelectedWebPartChangingEvent, value);
718 Events.RemoveHandler(SelectedWebPartChangingEvent, value);
723 WebCategory("Action"),
724 WebSysDescription(SR.WebPartManager_WebPartAdded)
726 public event WebPartEventHandler WebPartAdded {
728 Events.AddHandler(WebPartAddedEvent, value);
731 Events.RemoveHandler(WebPartAddedEvent, value);
736 WebCategory("Action"),
737 WebSysDescription(SR.WebPartManager_WebPartAdding)
739 public event WebPartAddingEventHandler WebPartAdding {
741 Events.AddHandler(WebPartAddingEvent, value);
744 Events.RemoveHandler(WebPartAddingEvent, value);
749 WebCategory("Action"),
750 WebSysDescription(SR.WebPartManager_WebPartClosed)
752 public event WebPartEventHandler WebPartClosed {
754 Events.AddHandler(WebPartClosedEvent, value);
757 Events.RemoveHandler(WebPartClosedEvent, value);
762 WebCategory("Action"),
763 WebSysDescription(SR.WebPartManager_WebPartClosing)
765 public event WebPartCancelEventHandler WebPartClosing {
767 Events.AddHandler(WebPartClosingEvent, value);
770 Events.RemoveHandler(WebPartClosingEvent, value);
775 WebCategory("Action"),
776 WebSysDescription(SR.WebPartManager_WebPartDeleted)
778 public event WebPartEventHandler WebPartDeleted {
780 Events.AddHandler(WebPartDeletedEvent, value);
783 Events.RemoveHandler(WebPartDeletedEvent, value);
788 WebCategory("Action"),
789 WebSysDescription(SR.WebPartManager_WebPartDeleting)
791 public event WebPartCancelEventHandler WebPartDeleting {
793 Events.AddHandler(WebPartDeletingEvent, value);
796 Events.RemoveHandler(WebPartDeletingEvent, value);
801 WebCategory("Action"),
802 WebSysDescription(SR.WebPartManager_WebPartMoved)
804 public event WebPartEventHandler WebPartMoved {
806 Events.AddHandler(WebPartMovedEvent, value);
809 Events.RemoveHandler(WebPartMovedEvent, value);
814 WebCategory("Action"),
815 WebSysDescription(SR.WebPartManager_WebPartMoving)
817 public event WebPartMovingEventHandler WebPartMoving {
819 Events.AddHandler(WebPartMovingEvent, value);
822 Events.RemoveHandler(WebPartMovingEvent, value);
827 WebCategory("Action"),
828 WebSysDescription(SR.WebPartManager_WebPartsConnected)
830 public event WebPartConnectionsEventHandler WebPartsConnected {
832 Events.AddHandler(WebPartsConnectedEvent, value);
835 Events.RemoveHandler(WebPartsConnectedEvent, value);
840 WebCategory("Action"),
841 WebSysDescription(SR.WebPartManager_WebPartsConnecting)
843 public event WebPartConnectionsCancelEventHandler WebPartsConnecting {
845 Events.AddHandler(WebPartsConnectingEvent, value);
848 Events.RemoveHandler(WebPartsConnectingEvent, value);
853 WebCategory("Action"),
854 WebSysDescription(SR.WebPartManager_WebPartsDisconnected)
856 public event WebPartConnectionsEventHandler WebPartsDisconnected {
858 Events.AddHandler(WebPartsDisconnectedEvent, value);
861 Events.RemoveHandler(WebPartsDisconnectedEvent, value);
866 WebCategory("Action"),
867 WebSysDescription(SR.WebPartManager_WebPartsDisconnecting)
869 public event WebPartConnectionsCancelEventHandler WebPartsDisconnecting {
871 Events.AddHandler(WebPartsDisconnectingEvent, value);
874 Events.RemoveHandler(WebPartsDisconnectingEvent, value);
878 protected virtual void ActivateConnections() {
880 // ActivateConnections() is called as a result of no user action, so the events
881 // should not be cancellable. (VSWhidbey 516012)
882 _allowEventCancellation = false;
883 foreach (WebPartConnection connection in ConnectionsToActivate()) {
884 connection.Activate();
888 _allowEventCancellation = true;
892 // Called by WebPartManagerInternals
893 internal void AddWebPart(WebPart webPart) {
894 ((WebPartManagerControlCollection)Controls).AddWebPart(webPart);
897 private WebPart AddDynamicWebPartToZone(WebPart webPart, WebPartZoneBase zone, int zoneIndex) {
898 Debug.Assert(Personalization.IsModifiable);
900 // Zone should not be set on a dynamic web part being added to the page for the first time
901 Debug.Assert(webPart.Zone == null);
903 // Only add WebPart if IsAuthorized(webPart) == true
904 if (!IsAuthorized(webPart)) {
908 WebPart newWebPart = CopyWebPart(webPart);
909 Internals.SetIsStatic(newWebPart, false);
910 Internals.SetIsShared(newWebPart, Personalization.Scope == PersonalizationScope.Shared);
912 AddWebPartToZone(newWebPart, zone, zoneIndex);
913 Internals.AddWebPart(newWebPart);
915 // We set the personalized properties on the added WebPart AFTER it has been added to the
916 // control tree, since we want to exactly recreate the process the WebPart will go through
917 // when it is added from Personalization.
918 Personalization.CopyPersonalizationState(webPart, newWebPart);
920 // Raise event at very end of Add method
921 OnWebPartAdded(new WebPartEventArgs(newWebPart));
926 // Returns the WebPart that was actually added. For an existing Closed WebPart, this is a reference
927 // to the webPart parameter. For a new DynamicWebPart, this will be a copy of the webPart parameter.
928 public WebPart AddWebPart(WebPart webPart, WebPartZoneBase zone, int zoneIndex) {
929 Personalization.EnsureEnabled(/* ensureModifiable */ true);
931 if (webPart == null) {
932 throw new ArgumentNullException("webPart");
934 // Do not check that Controls.Contains(webPart), since this will be called on a WebPart
935 // before it is added to the Controls collection.
937 throw new ArgumentNullException("zone");
939 if (_webPartZones.Contains(zone) == false) {
940 throw new ArgumentException(SR.GetString(SR.WebPartManager_MustRegister), "zone");
943 throw new ArgumentOutOfRangeException("zoneIndex");
945 if (webPart.Zone != null && !webPart.IsClosed) {
946 throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyInZone), "webPart");
949 WebPartAddingEventArgs e = new WebPartAddingEventArgs(webPart, zone, zoneIndex);
951 if (_allowEventCancellation && e.Cancel) {
955 WebPart addedWebPart;
957 // If a part is already in the controls collection, dynamic or static, just make it
958 // not closed and add it to the specified zone
959 if (Controls.Contains(webPart)) {
960 addedWebPart = webPart;
961 AddWebPartToZone(webPart, zone, zoneIndex);
962 OnWebPartAdded(new WebPartEventArgs(addedWebPart));
964 addedWebPart = AddDynamicWebPartToZone(webPart, zone, zoneIndex);
965 // OnWebPartAdded() is called by AddDynamicWebPartToZone
969 CheckPartZoneIndexes(zone);
976 /// Adds the part to the dictionary mapping zones to parts.
978 private void AddWebPartToDictionary(WebPart webPart) {
979 if (_partsForZone != null) {
980 string zoneID = Internals.GetZoneID(webPart);
981 if (!String.IsNullOrEmpty(zoneID)) {
982 SortedList partsForZone = (SortedList)(_partsForZone[zoneID]);
983 if (partsForZone == null) {
984 partsForZone = new SortedList(new WebPart.ZoneIndexComparer());
985 _partsForZone[zoneID] = partsForZone;
987 partsForZone.Add(webPart, null);
993 /// Adds a web part to a zone at the specified zoneIndex, and renumbers all the parts in the zone
996 private void AddWebPartToZone(WebPart webPart, WebPartZoneBase zone, int zoneIndex) {
997 Debug.Assert(webPart.Zone == null || webPart.IsClosed);
999 // All the parts for the zone
1000 IList allParts = GetAllWebPartsForZone(zone);
1002 // The parts for the zone that were actually rendered
1003 WebPartCollection renderedParts = GetWebPartsForZone(zone);
1005 // The zoneIndex parameter is the desired index in the renderedParts collection.
1006 // Calculate the destination index into the allParts collection. (VSWhidbey 77719)
1007 int allPartsDestinationIndex;
1008 if (zoneIndex < renderedParts.Count) {
1009 WebPart successor = renderedParts[zoneIndex];
1010 Debug.Assert(allParts.Contains(successor));
1011 allPartsDestinationIndex = allParts.IndexOf(successor);
1014 allPartsDestinationIndex = allParts.Count;
1017 // Renumber all parts in the zone, leaving room for the added part
1018 for (int i = 0; i < allPartsDestinationIndex; i++) {
1019 WebPart part = ((WebPart)allParts[i]);
1020 Internals.SetZoneIndex(part, i);
1022 for (int i = allPartsDestinationIndex; i < allParts.Count; i++) {
1023 WebPart part = ((WebPart)allParts[i]);
1024 Internals.SetZoneIndex(part, i + 1);
1027 // Set the part index and add to destination zone
1028 Internals.SetZoneIndex(webPart, allPartsDestinationIndex);
1029 Internals.SetZoneID(webPart, zone.ID);
1030 Internals.SetIsClosed(webPart, false);
1032 _hasDataChanged = true;
1034 AddWebPartToDictionary(webPart);
1037 public virtual void BeginWebPartConnecting(WebPart webPart) {
1038 Personalization.EnsureEnabled(/* ensureModifiable */ true);
1040 if (webPart == null) {
1041 throw new ArgumentNullException("webPart");
1044 if (webPart.IsClosed) {
1045 throw new ArgumentException(SR.GetString(SR.WebPartManager_CantBeginConnectingClosed), "webPart");
1048 if (!Controls.Contains(webPart)) {
1049 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
1052 if (DisplayMode != ConnectDisplayMode) {
1053 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_MustBeInConnect));
1056 if (webPart == SelectedWebPart) {
1057 throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyInConnect), "webPart");
1060 WebPartCancelEventArgs ce = new WebPartCancelEventArgs(webPart);
1061 OnSelectedWebPartChanging(ce);
1062 if (_allowEventCancellation && ce.Cancel) {
1066 if (SelectedWebPart != null) {
1067 EndWebPartConnecting();
1068 if (SelectedWebPart != null) {
1069 // The ConnectModeChange was cancelled
1074 SetSelectedWebPart(webPart);
1076 Internals.CallOnConnectModeChanged(webPart);
1078 OnSelectedWebPartChanged(new WebPartEventArgs(webPart));
1081 public virtual void BeginWebPartEditing(WebPart webPart) {
1082 Personalization.EnsureEnabled(/* ensureModifiable */ true);
1084 if (webPart == null) {
1085 throw new ArgumentNullException("webPart");
1088 if (webPart.IsClosed) {
1089 throw new ArgumentException(SR.GetString(SR.WebPartManager_CantBeginEditingClosed), "webPart");
1092 if (!Controls.Contains(webPart)) {
1093 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
1096 if (DisplayMode != EditDisplayMode) {
1097 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_MustBeInEdit));
1100 if (webPart == SelectedWebPart) {
1101 throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyInEdit), "webPart");
1104 WebPartCancelEventArgs ce = new WebPartCancelEventArgs(webPart);
1105 OnSelectedWebPartChanging(ce);
1106 if (_allowEventCancellation && ce.Cancel) {
1110 if (SelectedWebPart != null) {
1111 EndWebPartEditing();
1112 if (SelectedWebPart != null) {
1113 // The EditModeChange was cancelled
1118 SetSelectedWebPart(webPart);
1120 Internals.CallOnEditModeChanged(webPart);
1122 OnSelectedWebPartChanged(new WebPartEventArgs(webPart));
1127 /// Checks that the web parts in a zone are numbered sequentially. This invariant
1128 /// should hold at the exit of AddWebPart, CloseWebPart, DeleteWebPart, MoveWebPart, and RegisterZone.
1130 private void CheckPartZoneIndexes(WebPartZoneBase zone) {
1131 ICollection parts = GetAllWebPartsForZone(zone);
1133 foreach (WebPart part in parts) {
1134 if (part.ZoneIndex != index) {
1135 System.Text.StringBuilder builder = new System.Text.StringBuilder();
1136 builder.Append("Title\tZone\tZoneIndex");
1137 foreach (WebPart part2 in Controls) {
1138 string zoneTitle = (part2.Zone == null) ? "null" : part2.Zone.DisplayTitle;
1139 builder.Append(part2.DisplayTitle + "\t" + zoneTitle + "\t" + part2.ZoneIndex);
1141 Debug.Assert(false, builder.ToString());
1149 protected virtual bool CheckRenderClientScript() {
1150 bool renderClientScript = false;
1152 if (EnableClientScript && Page != null) {
1153 HttpBrowserCapabilities browserCaps = Page.Request.Browser;
1155 // Win32 IE5.5+ and JScript 5.5+
1156 if (browserCaps.Win32 && (browserCaps.MSDomVersion.CompareTo(new Version(5, 5)) >= 0)) {
1157 renderClientScript = true;
1161 return renderClientScript;
1164 // When a Zone is deleted, any web parts in that zone should move to the page catalog.
1166 private void CloseOrphanedParts() {
1167 // PERF: Use Controls instead of WebParts property, to avoid creating another collection
1168 if (HasControls()) {
1170 // CloseOrphanedParts() is called as a result of no user action, so the events
1171 // should not be cancellable. (VSWhidbey 516012)
1172 _allowEventCancellation = false;
1173 foreach (WebPart part in Controls) {
1174 if (part.IsOrphaned) {
1180 _allowEventCancellation = true;
1185 public bool CanConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1186 WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint) {
1187 return CanConnectWebParts(provider, providerConnectionPoint, consumer, consumerConnectionPoint, null);
1190 public virtual bool CanConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1191 WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint,
1192 WebPartTransformer transformer) {
1193 return CanConnectWebPartsCore(provider, providerConnectionPoint, consumer, consumerConnectionPoint,
1194 transformer, false);
1197 private bool CanConnectWebPartsCore(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1198 WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint,
1199 WebPartTransformer transformer, bool throwOnError) {
1200 if (!Personalization.IsModifiable) {
1202 // Will throw appropriate exception
1203 Personalization.EnsureEnabled(/* ensureModifiable */ true);
1210 if (provider == null) {
1211 throw new ArgumentNullException("provider");
1213 if (!Controls.Contains(provider)) {
1214 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "provider");
1217 if (consumer == null) {
1218 throw new ArgumentNullException("consumer");
1220 if (!Controls.Contains(consumer)) {
1221 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "consumer");
1224 if (providerConnectionPoint == null) {
1225 throw new ArgumentNullException("providerConnectionPoint");
1227 if (consumerConnectionPoint == null) {
1228 throw new ArgumentNullException("consumerConnectionPoint");
1231 Control providerControl = provider.ToControl();
1232 Control consumerControl = consumer.ToControl();
1234 if (providerConnectionPoint.ControlType != providerControl.GetType()) {
1235 throw new ArgumentException(SR.GetString(SR.WebPartManager_InvalidConnectionPoint), "providerConnectionPoint");
1237 if (consumerConnectionPoint.ControlType != consumerControl.GetType()) {
1238 throw new ArgumentException(SR.GetString(SR.WebPartManager_InvalidConnectionPoint), "consumerConnectionPoint");
1241 if (provider == consumer) {
1243 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectToSelf));
1250 if (provider.IsClosed) {
1252 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectClosed, provider.ID));
1259 if (consumer.IsClosed) {
1261 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectClosed, consumer.ID));
1268 if (!providerConnectionPoint.GetEnabled(providerControl)) {
1270 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_DisabledConnectionPoint, providerConnectionPoint.ID, provider.ID));
1277 if (!consumerConnectionPoint.GetEnabled(consumerControl)) {
1279 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_DisabledConnectionPoint, consumerConnectionPoint.ID, consumer.ID));
1286 // Check AllowsMultipleConnections on each ConnectionPoint
1287 if (!providerConnectionPoint.AllowsMultipleConnections) {
1288 foreach (WebPartConnection c in Connections) {
1289 if (c.Provider == provider && c.ProviderConnectionPoint == providerConnectionPoint) {
1291 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_Duplicate, providerConnectionPoint.ID, provider.ID));
1300 if (!consumerConnectionPoint.AllowsMultipleConnections) {
1301 foreach (WebPartConnection c in Connections) {
1302 if (c.Consumer == consumer && c.ConsumerConnectionPoint == consumerConnectionPoint) {
1304 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_Duplicate, consumerConnectionPoint.ID, consumer.ID));
1313 if (transformer == null) {
1314 if (providerConnectionPoint.InterfaceType != consumerConnectionPoint.InterfaceType) {
1316 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_NoCommonInterface,
1317 new string[] {providerConnectionPoint.DisplayName, provider.ID,
1318 consumerConnectionPoint.DisplayName, consumer.ID}));
1325 ConnectionInterfaceCollection secondaryInterfaces = providerConnectionPoint.GetSecondaryInterfaces(providerControl);
1326 if (!consumerConnectionPoint.SupportsConnection(consumerControl, secondaryInterfaces)) {
1328 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_IncompatibleSecondaryInterfaces, new string[] {
1329 consumerConnectionPoint.DisplayName, consumer.ID,
1330 providerConnectionPoint.DisplayName, provider.ID}));
1338 Type transformerType = transformer.GetType();
1340 if (!AvailableTransformers.Contains(transformerType)) {
1341 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_TransformerNotAvailable, transformerType.FullName));
1344 // Check matching interfaces on connection points and transformer attribute.
1345 // Note that we require the connection interfaces to match exactly. We do not match
1346 // a derived interface type. This is because we want to simplify the interface matching
1347 // algorithm when transformers are involved. If we allowed derived interfaces to match,
1348 // then we would to take into account the "closest" match if multiple transformers
1349 // have compatible interfaces.
1350 Type transformerConsumerType = WebPartTransformerAttribute.GetConsumerType(transformerType);
1351 Type transformerProviderType = WebPartTransformerAttribute.GetProviderType(transformerType);
1352 if (providerConnectionPoint.InterfaceType != transformerConsumerType) {
1354 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_IncompatibleProviderTransformer,
1355 providerConnectionPoint.DisplayName, provider.ID, transformerType.FullName));
1361 if (transformerProviderType != consumerConnectionPoint.InterfaceType) {
1363 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_IncompatibleConsumerTransformer,
1364 transformerType.FullName, consumerConnectionPoint.DisplayName, consumer.ID));
1371 // A transformer never provides any secondary interfaces
1372 if (!consumerConnectionPoint.SupportsConnection(consumerControl, ConnectionInterfaceCollection.Empty)) {
1374 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_ConsumerRequiresSecondaryInterfaces,
1375 consumerConnectionPoint.DisplayName, consumer.ID));
1387 public void CloseWebPart(WebPart webPart) {
1388 CloseOrDeleteWebPart(webPart, /* delete */ false);
1391 private void CloseOrDeleteWebPart(WebPart webPart, bool delete) {
1392 Personalization.EnsureEnabled(/* ensureModifiable */ true);
1394 if (webPart == null) {
1395 throw new ArgumentNullException("webPart");
1397 if (!Controls.Contains(webPart)) {
1398 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
1401 if (!delete && webPart.IsClosed) {
1402 // Throw an exception instead of just returning. If the shared user and per user close
1403 // a WebPart at the same time, then the WebPartZoneBase should not call CloseWebPart
1404 // if the WebPart is now closed.
1405 throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyClosed), "webPart");
1409 if (webPart.IsStatic) {
1410 // Can't delete static parts
1411 throw new ArgumentException(SR.GetString(SR.WebPartManager_CantDeleteStatic), "webPart");
1413 else if (webPart.IsShared && (Personalization.Scope == PersonalizationScope.User)) {
1414 // Can't delete shared part in user scope
1415 throw new ArgumentException(SR.GetString(SR.WebPartManager_CantDeleteSharedInUserScope), "webPart");
1419 WebPartCancelEventArgs ce = new WebPartCancelEventArgs(webPart);
1421 OnWebPartDeleting(ce);
1424 OnWebPartClosing(ce);
1426 if (_allowEventCancellation && ce.Cancel) {
1430 if ((DisplayMode == ConnectDisplayMode) && (webPart == SelectedWebPart)) {
1431 EndWebPartConnecting();
1432 if (SelectedWebPart != null) {
1433 // The ConnectModeChange was cancelled
1439 if ((DisplayMode == EditDisplayMode) && (webPart == SelectedWebPart)) {
1440 EndWebPartEditing();
1441 if (SelectedWebPart != null) {
1442 // The EditModeChange was cancelled
1448 Internals.CallOnDeleting(webPart);
1451 Internals.CallOnClosing(webPart);
1455 WebPartZoneBase zone = webPart.Zone;
1458 // If we are deleting a closed WebPart, it has already been removed from
1459 // its Zone, so there is no need to do it again.
1460 if (!webPart.IsClosed) {
1461 RemoveWebPartFromZone(webPart);
1464 DisconnectWebPart(webPart);
1467 Internals.RemoveWebPart(webPart);
1469 // Raise the WebPartDeleted event after changing the WebPart properties
1470 // The WebPartDeleting event is raised before changing the WebPart properties
1471 OnWebPartDeleted(new WebPartEventArgs(webPart));
1474 // Raise the WebPartClosed event after changing the WebPart properties
1475 // The WebPartClosing event is raised before changing the WebPart properties
1476 OnWebPartClosed(new WebPartEventArgs(webPart));
1481 CheckPartZoneIndexes(zone);
1486 private WebPartConnection[] ConnectionsToActivate() {
1487 // PERF: We could implement this with a sorted list to simplify the code
1489 ArrayList connectionsToActivate = new ArrayList();
1491 // Contains the connection IDs we have already seen
1492 HybridDictionary connectionIDs = new HybridDictionary(true /* caseInsensitive */);
1494 WebPartConnection[] connections = new WebPartConnection[StaticConnections.Count + DynamicConnections.Count];
1495 StaticConnections.CopyTo(connections, 0);
1496 DynamicConnections.CopyTo(connections, StaticConnections.Count);
1497 foreach (WebPartConnection connection in connections) {
1498 ConnectionsToActivateHelper(connection, connectionIDs, connectionsToActivate);
1501 // Check unshared connections for conflicts with shared connections
1502 // Maybe this should only be done in user scope
1503 WebPartConnection[] connectionsToActivateArray = (WebPartConnection[])connectionsToActivate.ToArray(typeof(WebPartConnection));
1504 foreach (WebPartConnection connection in connectionsToActivateArray) {
1505 if (connection.IsShared) {
1509 ArrayList connectionsToDelete = new ArrayList();
1510 foreach (WebPartConnection otherConnection in connectionsToActivate) {
1511 if (connection == otherConnection) {
1515 if (otherConnection.IsShared && connection.ConflictsWith(otherConnection)) {
1516 // Delete shared connection.
1517 connectionsToDelete.Add(otherConnection);
1521 foreach (WebPartConnection connectionToDelete in connectionsToDelete) {
1522 DisconnectWebParts(connectionToDelete);
1523 connectionsToActivate.Remove(connectionToDelete);
1527 // Check shared, nonstatic connections for conflicts with static connections
1528 connectionsToActivateArray = (WebPartConnection[])connectionsToActivate.ToArray(typeof(WebPartConnection));
1529 foreach (WebPartConnection connection in connectionsToActivateArray) {
1530 if (!connection.IsShared || connection.IsStatic) {
1534 ArrayList connectionsToDelete = new ArrayList();
1535 foreach (WebPartConnection otherConnection in connectionsToActivate) {
1536 if (connection == otherConnection) {
1540 if (otherConnection.IsStatic && connection.ConflictsWith(otherConnection)) {
1541 // Delete static connection.
1542 connectionsToDelete.Add(otherConnection);
1546 foreach (WebPartConnection connectionToDelete in connectionsToDelete) {
1547 DisconnectWebParts(connectionToDelete);
1548 connectionsToActivate.Remove(connectionToDelete);
1552 // Check all remaining connections for conflicts. Any conflicts at this stage will
1553 // cause an error to be rendered in the consumer WebPart, and the conflicting connections
1554 // will not be activated.
1555 ArrayList finalConnectionsToActivate = new ArrayList();
1556 foreach (WebPartConnection connection in connectionsToActivate) {
1557 bool hasConflict = false;
1559 foreach (WebPartConnection otherConnection in connectionsToActivate) {
1560 if (connection == otherConnection) {
1564 if (connection.ConflictsWithConsumer(otherConnection)) {
1565 connection.Consumer.SetConnectErrorMessage(SR.GetString(SR.WebPartConnection_Duplicate, connection.ConsumerConnectionPoint.DisplayName,
1566 connection.Consumer.DisplayTitle));
1570 if (connection.ConflictsWithProvider(otherConnection)) {
1571 connection.Consumer.SetConnectErrorMessage(SR.GetString(SR.WebPartConnection_Duplicate, connection.ProviderConnectionPoint.DisplayName,
1572 connection.Provider.DisplayTitle));
1578 finalConnectionsToActivate.Add(connection);
1582 // Don't allow the user to modify the StaticConnections collection after its connections have
1583 // been activated. Use property instead of field to force creation of collection.
1584 StaticConnections.SetReadOnly(SR.WebPartManager_StaticConnectionsReadOnly);
1586 // The user can't directly change the DynamicConnections property since it is internal.
1587 // Make it read-only in case we have a bug and try to change it after activation.
1588 // We check the read-only status of this collection in ConnectWebParts() and DisconnectWebParts().
1589 DynamicConnections.SetReadOnly(SR.WebPartManager_DynamicConnectionsReadOnly);
1591 return (WebPartConnection[])finalConnectionsToActivate.ToArray(typeof(WebPartConnection));
1594 // If we think we should activate the connection, adds it to the dictionary under the key
1595 // for its provider and consumer connection points.
1596 private void ConnectionsToActivateHelper(WebPartConnection connection, IDictionary connectionIDs,
1597 ArrayList connectionsToActivate) {
1598 string connectionID = connection.ID;
1600 if (String.IsNullOrEmpty(connectionID)) {
1601 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_NoID));
1604 if (connectionIDs.Contains(connectionID)) {
1605 throw new InvalidOperationException(
1606 SR.GetString(SR.WebPartManager_DuplicateConnectionID, connectionID));
1608 connectionIDs.Add(connectionID, null);
1610 if (connection.Deleted) {
1614 WebPart providerWebPart = connection.Provider;
1615 if (providerWebPart == null) {
1616 if (connection.IsStatic) {
1617 // throw an exception, to alert the developer that his static connection is invalid
1618 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_NoProvider, connection.ProviderID));
1621 // Silently delete the connection, since this is a valid runtime scenario.
1622 // A connected web part may have been deleted.
1623 DisconnectWebParts(connection);
1628 WebPart consumerWebPart = connection.Consumer;
1629 if (consumerWebPart == null) {
1630 if (connection.IsStatic) {
1631 // throw an exception, to alert the developer that his static connection is invalid
1632 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_NoConsumer, connection.ConsumerID));
1635 // Silently delete the connection, since this is a valid runtime scenario.
1636 // A connected web part may have been deleted.
1637 DisconnectWebParts(connection);
1642 // Do not activate connections involving ProxyWebParts
1643 if (providerWebPart is ProxyWebPart || consumerWebPart is ProxyWebPart) {
1647 Control providerControl = providerWebPart.ToControl();
1648 Control consumerControl = consumerWebPart.ToControl();
1650 // Cannot connect a WebPart to itself
1651 if (providerControl == consumerControl) {
1652 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectToSelf));
1655 ProviderConnectionPoint providerConnectionPoint = connection.ProviderConnectionPoint;
1656 if (providerConnectionPoint == null) {
1657 consumerWebPart.SetConnectErrorMessage(SR.GetString(SR.WebPartConnection_NoProviderConnectionPoint, connection.ProviderConnectionPointID,
1658 providerWebPart.DisplayTitle));
1661 // Don't need to check that providerConnectionPoint is enabled, since this will be checked
1662 // in WebPartConnection.Activate().
1664 ConsumerConnectionPoint consumerConnectionPoint = connection.ConsumerConnectionPoint;
1665 if (consumerConnectionPoint == null) {
1666 consumerWebPart.SetConnectErrorMessage(SR.GetString(SR.WebPartConnection_NoConsumerConnectionPoint, connection.ConsumerConnectionPointID,
1667 consumerWebPart.DisplayTitle));
1670 // Don't need to check that consumer ConnectionPoint is enabled, since this will be checked
1671 // in WebPartConnection.Activate().
1673 connectionsToActivate.Add(connection);
1676 public WebPartConnection ConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1677 WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint) {
1678 return ConnectWebParts(provider, providerConnectionPoint, consumer, consumerConnectionPoint, null);
1681 public virtual WebPartConnection ConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1682 WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint,
1683 WebPartTransformer transformer) {
1684 CanConnectWebPartsCore(provider, providerConnectionPoint, consumer, consumerConnectionPoint,
1685 transformer, /*throwOnError*/ true);
1687 if (DynamicConnections.IsReadOnly) {
1688 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_ConnectTooLate));
1691 WebPartConnectionsCancelEventArgs ce = new WebPartConnectionsCancelEventArgs(
1692 provider, providerConnectionPoint, consumer, consumerConnectionPoint);
1693 OnWebPartsConnecting(ce);
1694 if (_allowEventCancellation && ce.Cancel) {
1698 Control providerControl = provider.ToControl();
1699 Control consumerControl = consumer.ToControl();
1701 WebPartConnection connection = new WebPartConnection();
1702 connection.ID = CreateDynamicConnectionID();
1703 connection.ProviderID = providerControl.ID;
1704 connection.ConsumerID = consumerControl.ID;
1705 connection.ProviderConnectionPointID = providerConnectionPoint.ID;
1706 connection.ConsumerConnectionPointID = consumerConnectionPoint.ID;
1708 if (transformer != null) {
1709 Internals.SetTransformer(connection, transformer);
1712 Internals.SetIsShared(connection, Personalization.Scope == PersonalizationScope.Shared);
1713 Internals.SetIsStatic(connection, false);
1715 DynamicConnections.Add(connection);
1716 _hasDataChanged = true;
1718 OnWebPartsConnected(new WebPartConnectionsEventArgs(provider, providerConnectionPoint,
1719 consumer, consumerConnectionPoint, connection));
1724 // Returns a copy of the WebPart, with all the properties reset to their default value.
1725 // If the WebPart is a GenericWebPart, returns a copy of the GenericWebPart and a copy of the
1726 // ChildControl inside the GenericWebPart. The ID of the new WebPart and ChildControl should
1727 // be set to a value obtained from CreateDynamicWebPartID.
1728 // Virtual because a derived WebPartManager will deserialize a WebPart from XML in this method.
1729 protected virtual WebPart CopyWebPart(WebPart webPart) {
1732 GenericWebPart genericWebPart = webPart as GenericWebPart;
1733 if (genericWebPart != null) {
1734 Control childControl = genericWebPart.ChildControl;
1735 VerifyType(childControl);
1736 Type childControlType = childControl.GetType();
1737 Control newChildControl = (Control)Internals.CreateObjectFromType(childControlType);
1738 newChildControl.ID = CreateDynamicWebPartID(childControlType);
1740 newWebPart = CreateWebPart(newChildControl);
1743 VerifyType(webPart);
1744 newWebPart = (WebPart)Internals.CreateObjectFromType(webPart.GetType());
1747 newWebPart.ID = CreateDynamicWebPartID(webPart.GetType());
1752 protected virtual TransformerTypeCollection CreateAvailableTransformers() {
1753 TransformerTypeCollection availableTransformers = new TransformerTypeCollection();
1755 WebPartsSection configSection = RuntimeConfig.GetConfig().WebParts;
1757 IDictionary transformers = configSection.Transformers.GetTransformerEntries();
1759 foreach (Type type in transformers.Values) {
1760 availableTransformers.Add(type);
1763 return availableTransformers;
1766 // Returns an array of ICollection objects. The first is the ConsumerConnectionPoints, the
1767 // second is the ProviderConnectionPoints.
1768 private static ICollection[] CreateConnectionPoints(Type type) {
1769 ArrayList consumerConnectionPoints = new ArrayList();
1770 ArrayList providerConnectionPoints = new ArrayList();
1772 MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
1773 foreach (MethodInfo method in methods) {
1775 // Create consumer connection points
1776 object[] consumerAttributes = method.GetCustomAttributes(typeof(ConnectionConsumerAttribute), true);
1777 // ConnectionConsumerAttribute.AllowMultiple is false
1778 Debug.Assert(consumerAttributes.Length == 0 || consumerAttributes.Length == 1);
1779 if (consumerAttributes.Length == 1) {
1780 // Consumer signature: method is public, return type is void, takes one parameter
1781 ParameterInfo[] parameters = method.GetParameters();
1782 Type parameterType = null;
1783 if (parameters.Length == 1) {
1784 parameterType = parameters[0].ParameterType;
1787 if (method.IsPublic && method.ReturnType == typeof(void) && parameterType != null) {
1788 ConnectionConsumerAttribute attribute = consumerAttributes[0] as ConnectionConsumerAttribute;
1789 String displayName = attribute.DisplayName;
1790 String id = attribute.ID;
1791 Type connectionPointType = attribute.ConnectionPointType;
1792 bool allowsMultipleConnections = attribute.AllowsMultipleConnections;
1793 ConsumerConnectionPoint connectionPoint;
1794 if (connectionPointType == null) {
1795 connectionPoint = new ConsumerConnectionPoint(method, parameterType, type,
1796 displayName, id, allowsMultipleConnections);
1799 // The ConnectionPointType is validated in the attribute property getter
1800 Object[] args = new Object[] { method, parameterType, type, displayName, id, allowsMultipleConnections };
1801 connectionPoint = (ConsumerConnectionPoint)Activator.CreateInstance(connectionPointType, args);
1803 consumerConnectionPoints.Add(connectionPoint);
1806 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_InvalidConsumerSignature, method.Name, type.FullName));
1810 // Create provider connection points
1811 object[] providerAttributes = method.GetCustomAttributes(typeof(ConnectionProviderAttribute), true);
1812 // ConnectionProviderAttribute.AllowMultiple is false
1813 Debug.Assert(providerAttributes.Length == 0 || providerAttributes.Length == 1);
1814 if (providerAttributes.Length == 1) {
1815 // Provider signature: method is public, return type is an object, and takes no parameters
1816 Type returnType = method.ReturnType;
1817 if (method.IsPublic && returnType != typeof(void) && method.GetParameters().Length == 0) {
1818 ConnectionProviderAttribute attribute = providerAttributes[0] as ConnectionProviderAttribute;
1819 String displayName = attribute.DisplayName;
1820 String id = attribute.ID;
1821 Type connectionPointType = attribute.ConnectionPointType;
1822 bool allowsMultipleConnections = attribute.AllowsMultipleConnections;
1823 ProviderConnectionPoint connectionPoint;
1824 if (connectionPointType == null) {
1825 connectionPoint = new ProviderConnectionPoint(method, returnType, type,
1826 displayName, id, allowsMultipleConnections);
1829 // The ConnectionPointType is validated in the attribute property getter
1830 Object[] args = new Object[] { method, returnType, type, displayName, id, allowsMultipleConnections };
1831 connectionPoint = (ProviderConnectionPoint)Activator.CreateInstance(connectionPointType, args);
1833 providerConnectionPoints.Add(connectionPoint);
1836 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_InvalidProviderSignature, method.Name, type.FullName));
1841 return new ICollection[] { new ConsumerConnectionPointCollection(consumerConnectionPoints),
1842 new ProviderConnectionPointCollection(providerConnectionPoints) };
1845 protected sealed override ControlCollection CreateControlCollection() {
1846 return new WebPartManagerControlCollection(this);
1850 /// Can be overridden by derived types, to add additional display modes. Display modes
1851 /// should be added in the order they are to appear in the page menu.
1853 protected virtual WebPartDisplayModeCollection CreateDisplayModes() {
1854 WebPartDisplayModeCollection displayModes = new WebPartDisplayModeCollection();
1856 displayModes.Add(BrowseDisplayMode);
1857 displayModes.Add(CatalogDisplayMode);
1858 displayModes.Add(DesignDisplayMode);
1859 displayModes.Add(EditDisplayMode);
1860 displayModes.Add(ConnectDisplayMode);
1862 return displayModes;
1865 private string CreateDisplayTitle(string title, WebPart webPart, int count) {
1866 string displayTitle = title;
1868 if (webPart.Hidden) {
1869 displayTitle = SR.GetString(SR.WebPart_HiddenFormatString, displayTitle);
1872 if (webPart is ErrorWebPart) {
1873 displayTitle = SR.GetString(SR.WebPart_ErrorFormatString, displayTitle);
1877 if (count < displayTitleSuffix.Length) {
1878 displayTitle += displayTitleSuffix[count];
1881 displayTitle += " [" + count.ToString(CultureInfo.CurrentCulture) + "]";
1885 return displayTitle;
1888 private IDictionary CreateDisplayTitles() {
1889 Hashtable displayTitles = new Hashtable();
1891 Hashtable titles = new Hashtable();
1892 foreach (WebPart part in Controls) {
1893 string title = part.Title;
1894 if (String.IsNullOrEmpty(title)) {
1895 title = SR.GetString(SR.Part_Untitled);
1898 if (part is UnauthorizedWebPart) {
1899 displayTitles[part] = title;
1903 ArrayList parts = (ArrayList)titles[title];
1904 if (parts == null) {
1905 parts = new ArrayList();
1906 titles[title] = parts;
1907 displayTitles[part] = CreateDisplayTitle(title, part, 0);
1910 int count = parts.Count;
1912 WebPart firstPart = (WebPart)parts[0];
1913 displayTitles[firstPart] = CreateDisplayTitle(title, firstPart, 1);
1915 displayTitles[part] = CreateDisplayTitle(title, part, count + 1);
1921 return displayTitles;
1924 protected virtual string CreateDynamicConnectionID() {
1925 Debug.Assert(Personalization.IsModifiable);
1927 int guidHash = Math.Abs(Guid.NewGuid().GetHashCode());
1928 return DynamicConnectionIDPrefix + guidHash.ToString(CultureInfo.InvariantCulture);
1931 protected virtual string CreateDynamicWebPartID(Type webPartType) {
1932 if (webPartType == null) {
1933 throw new ArgumentNullException("webPartType");
1936 Debug.Assert(Personalization.IsModifiable);
1940 int guidHash = Math.Abs(Guid.NewGuid().GetHashCode());
1941 string id = DynamicWebPartIDPrefix + guidHash.ToString(CultureInfo.InvariantCulture);
1943 if (Page != null && Page.Trace.IsEnabled) {
1944 id += webPartType.Name;
1950 protected virtual ErrorWebPart CreateErrorWebPart(string originalID, string originalTypeName,
1951 string originalPath, string genericWebPartID,
1952 string errorMessage) {
1953 ErrorWebPart errorWebPart = new ErrorWebPart(originalID, originalTypeName, originalPath, genericWebPartID);
1954 errorWebPart.ErrorMessage = errorMessage;
1955 return errorWebPart;
1960 protected virtual WebPartPersonalization CreatePersonalization() {
1961 return new WebPartPersonalization(this);
1965 /// Wraps the control in a GenericWebPart, and returns the GenericWebPart. Virtual so it can be
1966 /// overridden to use a derived type of GenericWebPart instead. Needs to be public so it can
1967 /// be called by the page developer.
1969 public virtual GenericWebPart CreateWebPart(Control control) {
1970 return CreateWebPartStatic(control);
1973 // Called by other WebParts classes to create a GenericWebPart, if they do not have
1974 // a reference to a WebPartManager (i.e. at design time). This method centralizes
1975 // the creation of GenericWebParts.
1976 internal static GenericWebPart CreateWebPartStatic(Control control) {
1977 GenericWebPart genericWebPart = new GenericWebPart(control);
1979 // The ChildControl should be added to the GenericWebPart.Controls collection when CreateWebPart()
1980 // is called, instead of waiting until the GenericWebPart.Controls collection is accessed.
1981 // This is necessary since the caller has a direct reference to the ChildControl, and may
1982 // perform operations on the ChildControl that assume the ChildControl is parented.
1983 // (VSWhidbey 498039)
1984 genericWebPart.CreateChildControls();
1986 return genericWebPart;
1989 public void DeleteWebPart(WebPart webPart) {
1990 CloseOrDeleteWebPart(webPart, /* delete */ true);
1993 // Disconnects all connections involving the Web Part
1994 protected virtual void DisconnectWebPart(WebPart webPart) {
1996 // We cannot allow any of the WebPartsDisconnecting events to be cancelled, since we may have already
1997 // disconnected some connections before we hit the one that needs to be cancelled. (VSWhidbey 516012)
1998 _allowEventCancellation = false;
1999 foreach (WebPartConnection connection in Connections) {
2000 if (connection.Provider == webPart || connection.Consumer == webPart) {
2001 DisconnectWebParts(connection);
2006 _allowEventCancellation = true;
2010 public virtual void DisconnectWebParts(WebPartConnection connection) {
2011 Personalization.EnsureEnabled(/* ensureModifiable */ true);
2013 if (connection == null) {
2014 throw new ArgumentNullException("connection");
2017 Debug.Assert(!(StaticConnections.Contains(connection) && DynamicConnections.Contains(connection)));
2019 WebPart provider = connection.Provider;
2020 ProviderConnectionPoint providerConnectionPoint = connection.ProviderConnectionPoint;
2021 WebPart consumer = connection.Consumer;
2022 ConsumerConnectionPoint consumerConnectionPoint = connection.ConsumerConnectionPoint;
2024 WebPartConnectionsCancelEventArgs ce = new WebPartConnectionsCancelEventArgs(
2025 provider, providerConnectionPoint, consumer, consumerConnectionPoint, connection);
2026 OnWebPartsDisconnecting(ce);
2027 if (_allowEventCancellation && ce.Cancel) {
2031 WebPartConnectionsEventArgs eventArgs = new WebPartConnectionsEventArgs(
2032 provider, providerConnectionPoint, consumer, consumerConnectionPoint);
2034 if (StaticConnections.Contains(connection)) {
2035 if (StaticConnections.IsReadOnly) {
2036 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DisconnectTooLate));
2038 if (Internals.ConnectionDeleted(connection)) {
2039 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_AlreadyDisconnected));
2041 Internals.DeleteConnection(connection);
2042 _hasDataChanged = true;
2043 OnWebPartsDisconnected(eventArgs);
2045 else if (DynamicConnections.Contains(connection)) {
2046 if (DynamicConnections.IsReadOnly) {
2047 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DisconnectTooLate));
2050 if (ShouldRemoveConnection(connection)) {
2051 // Unshared dynamic connection should never be disabled
2052 Debug.Assert(!Internals.ConnectionDeleted(connection));
2053 DynamicConnections.Remove(connection);
2056 if (Internals.ConnectionDeleted(connection)) {
2057 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_AlreadyDisconnected));
2059 Internals.DeleteConnection(connection);
2061 _hasDataChanged = true;
2062 OnWebPartsDisconnected(eventArgs);
2065 throw new ArgumentException(SR.GetString(SR.WebPartManager_UnknownConnection), "connection");
2069 public virtual void EndWebPartConnecting() {
2070 Personalization.EnsureEnabled(/* ensureModifiable */ true);
2072 WebPart selectedWebPart = SelectedWebPart;
2074 if (selectedWebPart == null) {
2075 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoSelectedWebPartConnect));
2078 WebPartCancelEventArgs ce = new WebPartCancelEventArgs(selectedWebPart);
2079 OnSelectedWebPartChanging(ce);
2081 if (_allowEventCancellation && ce.Cancel) {
2085 SetSelectedWebPart(null);
2087 Internals.CallOnConnectModeChanged(selectedWebPart);
2089 // The EventArg should always contain the new SelectedWebPart, so it should contain null
2090 // when we are ending connecting.
2091 OnSelectedWebPartChanged(new WebPartEventArgs(null));
2094 public virtual void EndWebPartEditing() {
2095 Personalization.EnsureEnabled(/* ensureModifiable */ true);
2097 WebPart selectedWebPart = SelectedWebPart;
2099 if (selectedWebPart == null) {
2100 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoSelectedWebPartEdit));
2103 WebPartCancelEventArgs ce = new WebPartCancelEventArgs(selectedWebPart);
2104 OnSelectedWebPartChanging(ce);
2106 if (_allowEventCancellation && ce.Cancel) {
2110 SetSelectedWebPart(null);
2112 Internals.CallOnEditModeChanged(selectedWebPart);
2114 // The EventArg should always contain the new SelectedWebPart, so it should contain null
2115 // when we are ending editing.
2116 OnSelectedWebPartChanged(new WebPartEventArgs(null));
2119 public virtual void ExportWebPart(WebPart webPart, XmlWriter writer) {
2120 // Personalization.EnsureEnabled(/* ensureModifiable */ false);
2122 if (webPart == null) {
2123 throw new ArgumentNullException("webPart");
2125 if (!Controls.Contains(webPart)) {
2126 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
2129 if (writer == null) {
2130 throw new ArgumentNullException("writer");
2132 if (webPart.ExportMode == WebPartExportMode.None) {
2133 throw new ArgumentException(SR.GetString(SR.WebPartManager_PartNotExportable), "webPart");
2135 bool excludeSensitive = (webPart.ExportMode == WebPartExportMode.NonSensitiveData &&
2136 !(Personalization.Scope == PersonalizationScope.Shared));
2138 // Write the root elements
2139 writer.WriteStartElement(ExportRootElement);
2140 writer.WriteStartElement(ExportPartElement);
2141 writer.WriteAttributeString(ExportPartNamespaceAttribute, ExportPartNamespaceValue);
2143 writer.WriteStartElement(ExportMetaDataElement);
2144 writer.WriteStartElement(ExportTypeElement);
2145 Control control = webPart.ToControl();
2146 UserControl userControl = control as UserControl;
2147 if (userControl != null) {
2148 writer.WriteAttributeString(ExportUserControlSrcAttribute, userControl.AppRelativeVirtualPath);
2151 writer.WriteAttributeString(ExportTypeNameAttribute, WebPartUtil.SerializeType(control.GetType()));
2153 writer.WriteEndElement(); //type
2154 writer.WriteElementString(ExportErrorMessageElement, webPart.ImportErrorMessage);
2155 writer.WriteEndElement(); //metadata
2157 writer.WriteStartElement(ExportDataElement);
2158 // We get the personalization data for the current page personalization mode
2159 IDictionary propBag = PersonalizableAttribute.GetPersonalizablePropertyValues(webPart, PersonalizationScope.Shared, excludeSensitive);
2161 writer.WriteStartElement(ExportPropertiesElement);
2163 // Special case GenericWebPart
2164 GenericWebPart genericWebPart = webPart as GenericWebPart;
2166 if (genericWebPart != null) {
2168 // Export IPersonalizable user control data first
2169 ExportIPersonalizable(writer, control, excludeSensitive);
2171 IDictionary controlData = PersonalizableAttribute.GetPersonalizablePropertyValues(control,
2172 PersonalizationScope.Shared,
2174 ExportToWriter(controlData, writer);
2175 writer.WriteEndElement(); //properties
2176 writer.WriteStartElement(ExportGenericPartPropertiesElement);
2177 // Export IPersonalizable part data first
2178 ExportIPersonalizable(writer, webPart, excludeSensitive);
2179 ExportToWriter(propBag, writer);
2182 // Export IPersonalizable part data first
2183 ExportIPersonalizable(writer, webPart, excludeSensitive);
2184 ExportToWriter(propBag, writer);
2186 writer.WriteEndElement(); //properties or genericWebPartProperties
2187 writer.WriteEndElement(); //data
2188 writer.WriteEndElement(); //webpart
2189 writer.WriteEndElement(); //webparts
2192 private void ExportIPersonalizable(XmlWriter writer, Control control, bool excludeSensitive) {
2193 IPersonalizable personalizableControl = control as IPersonalizable;
2194 if (personalizableControl != null) {
2195 PersonalizationDictionary personalizableData = new PersonalizationDictionary();
2196 personalizableControl.Save(personalizableData);
2197 if (personalizableData.Count > 0) {
2198 writer.WriteStartElement(ExportIPersonalizableElement);
2199 ExportToWriter(personalizableData, writer, /* isIPersonalizable */ true, excludeSensitive);
2200 writer.WriteEndElement(); // ipersonalizable
2205 private static void ExportProperty(XmlWriter writer, string name, string value, Type type,
2206 PersonalizationScope scope, bool isIPersonalizable) {
2208 writer.WriteStartElement(ExportPropertyElement);
2209 writer.WriteAttributeString(ExportPropertyNameAttribute, name);
2210 writer.WriteAttributeString(ExportPropertyTypeAttribute, GetExportName(type));
2211 if (isIPersonalizable) {
2212 writer.WriteAttributeString(ExportPropertyScopeAttribute, scope.ToString());
2214 if (value == null) {
2215 writer.WriteAttributeString(ExportPropertyNullAttribute, "true");
2218 writer.WriteString(value);
2220 writer.WriteEndElement(); //property
2223 private void ExportToWriter(IDictionary propBag, XmlWriter writer) {
2224 ExportToWriter(propBag, writer, false, false);
2227 private void ExportToWriter(IDictionary propBag,
2229 bool isIPersonalizable,
2230 bool excludeSensitive) {
2231 // We only honor excludeSensitive if isIpersonalizable is true.
2232 Debug.Assert((!excludeSensitive) || isIPersonalizable);
2234 // Work on each property in the persomalization data
2235 foreach(DictionaryEntry entry in propBag) {
2236 string name = (string)entry.Key;
2237 if (name == AuthorizationFilterName || name == ImportErrorMessageName) {
2241 PropertyInfo pi = null;
2243 Pair data = entry.Value as Pair;
2244 PersonalizationScope scope = PersonalizationScope.User;
2245 // We expect a pair if not exporting types
2246 // (which happens only for non-IPersonalizable data)
2247 if (isIPersonalizable == false && data != null) {
2248 pi = (PropertyInfo)data.First;
2251 else if (isIPersonalizable) {
2252 PersonalizationEntry personalizationEntry = entry.Value as PersonalizationEntry;
2253 if (personalizationEntry != null &&
2254 (Personalization.Scope == PersonalizationScope.Shared ||
2255 personalizationEntry.Scope == PersonalizationScope.User)) {
2257 val = personalizationEntry.Value;
2258 scope = personalizationEntry.Scope;
2260 if (excludeSensitive && personalizationEntry.IsSensitive) {
2264 // we get the type from the PropertyInfo if we have it, or from the value if it's not null, or we use object.
2265 Type valType = ((pi != null) ? pi.PropertyType : ((val != null) ? val.GetType() : typeof(object)));
2267 string exportString;
2268 if (ShouldExportProperty(pi, valType, val, out exportString)) {
2269 ExportProperty(writer, name, exportString, valType, scope, isIPersonalizable);
2275 EditorBrowsable(EditorBrowsableState.Never),
2277 public override void Focus() {
2278 throw new NotSupportedException(SR.GetString(SR.NoFocusSupport, this.GetType().Name));
2282 /// Returns all the web parts in a zone, excluding closed web parts.
2283 /// Since this is only a private method, return an IList instead of a WebPartCollection
2284 /// for better performance.
2286 private IList GetAllWebPartsForZone(WebPartZoneBase zone) {
2287 if (_partsForZone == null) {
2288 _partsForZone = new HybridDictionary(true /* caseInsensitive */);
2289 foreach (WebPart part in Controls) {
2290 if (!part.IsClosed) {
2291 string zoneID = Internals.GetZoneID(part);
2292 Debug.Assert(!String.IsNullOrEmpty(zoneID));
2293 if (!String.IsNullOrEmpty(zoneID)) {
2294 SortedList partsForZone = (SortedList)_partsForZone[zoneID];
2295 if (partsForZone == null) {
2296 partsForZone = new SortedList(new WebPart.ZoneIndexComparer());
2297 _partsForZone[zoneID] = partsForZone;
2299 partsForZone.Add(part, null);
2305 SortedList parts = (SortedList)_partsForZone[zone.ID];
2306 if (parts == null) {
2307 parts = new SortedList();
2310 return parts.GetKeyList();
2313 private static ICollection[] GetConnectionPoints(Type type) {
2314 if (ConnectionPointsCache == null) {
2315 // I don't think there is a race condition here. Even if multiple threads enter this block
2316 // at the same time, the worst thing that can happen is that the ConnectionPointsCache gets
2317 // replaced by a new Hashtable(), and existing entries will need to be recomputed.
2318 // There is no way for the ConnectionPointsCache to become null.
2319 ConnectionPointsCache = Hashtable.Synchronized(new Hashtable());
2322 // DevDiv Bugs 38677: Cache by culture and type as it may vary by culture within this app
2323 ConnectionPointKey connectionPointKey = new ConnectionPointKey(type, CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
2325 ICollection[] connectionPoints = (ICollection[])ConnectionPointsCache[connectionPointKey];
2326 if (connectionPoints == null) {
2327 connectionPoints = CreateConnectionPoints(type);
2328 ConnectionPointsCache[connectionPointKey] = connectionPoints;
2331 return connectionPoints;
2334 internal ConsumerConnectionPoint GetConsumerConnectionPoint(WebPart webPart, string connectionPointID) {
2335 ConsumerConnectionPointCollection points = GetConsumerConnectionPoints(webPart);
2336 if (points != null && points.Count > 0) {
2337 return points[connectionPointID];
2344 public virtual ConsumerConnectionPointCollection GetConsumerConnectionPoints(WebPart webPart) {
2345 if (webPart == null) {
2346 throw new ArgumentNullException("webPart");
2348 // Do not check that Controls.Contains(webPart), since this may be called on a WebPart
2349 // outside of a Zone. Also, this method shouldn't really care whether the WebPart is
2350 // inside the WebPartManager.
2352 return GetConsumerConnectionPoints(webPart.ToControl().GetType());
2355 private static ConsumerConnectionPointCollection GetConsumerConnectionPoints(Type type) {
2356 ICollection[] connectionPoints = GetConnectionPoints(type);
2357 return (ConsumerConnectionPointCollection)connectionPoints[0];
2360 public static WebPartManager GetCurrentWebPartManager(Page page) {
2362 throw new ArgumentNullException("page");
2365 return page.Items[typeof(WebPartManager)] as WebPartManager;
2368 // Before PreRender, return String.Empty.
2369 // On first call to this function after PreRender, compute DisplayTitle for all WebParts
2370 // and save it in a dictionary. WebPart.DisplayTitle is nonvirtual and calls this method every time.
2371 // A derived WebPartManager can override this method to compute and store DisplayTitle any way it
2372 // sees fit. It could compute the values sooner than PreRender.
2373 protected internal virtual string GetDisplayTitle(WebPart webPart) {
2374 if (webPart == null) {
2375 throw new ArgumentNullException("webPart");
2377 if (!Controls.Contains(webPart)) {
2378 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
2381 if (!_allowCreateDisplayTitles) {
2382 return String.Empty;
2385 if (_displayTitles == null) {
2386 _displayTitles = CreateDisplayTitles();
2389 string displayTitle = (string)_displayTitles[webPart];
2390 Debug.Assert(!String.IsNullOrEmpty(displayTitle));
2391 return displayTitle;
2394 private static ICollection GetEnabledConnectionPoints(ICollection connectionPoints, WebPart webPart) {
2395 Control control = webPart.ToControl();
2396 ArrayList enabledPoints = new ArrayList();
2397 foreach (ConnectionPoint point in connectionPoints) {
2398 if (point.GetEnabled(control)) {
2399 enabledPoints.Add(point);
2402 return enabledPoints;
2405 internal ConsumerConnectionPointCollection GetEnabledConsumerConnectionPoints(WebPart webPart) {
2406 ICollection enabledPoints = GetEnabledConnectionPoints(GetConsumerConnectionPoints(webPart), webPart);
2407 return new ConsumerConnectionPointCollection(enabledPoints);
2410 internal ProviderConnectionPointCollection GetEnabledProviderConnectionPoints(WebPart webPart) {
2411 ICollection enabledPoints = GetEnabledConnectionPoints(GetProviderConnectionPoints(webPart), webPart);
2412 return new ProviderConnectionPointCollection(enabledPoints);
2415 public string GetExportUrl(WebPart webPart) {
2416 string personalizationScope =
2417 (Personalization.Scope == PersonalizationScope.Shared) ? "&scope=shared" : String.Empty;
2418 string queryString = Page.Request.QueryStringText;
2420 return Page.Request.FilePath + "?" + Page.WebPartExportID + "=true&webPart=" +
2421 HttpUtility.UrlEncode(webPart.ID) +
2422 (!String.IsNullOrEmpty(queryString) ?
2423 "&query=" + HttpUtility.UrlEncode(queryString) :
2425 personalizationScope;
2428 private static Type GetExportType(string name) {
2430 case ExportTypeString:
2431 return typeof(string);
2434 case ExportTypeBool:
2435 return typeof(bool);
2436 case ExportTypeDouble:
2437 return typeof(double);
2438 case ExportTypeSingle:
2439 return typeof(Single);
2440 case ExportTypeDateTime:
2441 return typeof(DateTime);
2442 case ExportTypeColor:
2443 return typeof(Color);
2444 case ExportTypeUnit:
2445 return typeof(Unit);
2446 case ExportTypeFontSize:
2447 return typeof(FontSize);
2448 case ExportTypeDirection:
2449 return typeof(ContentDirection);
2450 case ExportTypeHelpMode:
2451 return typeof(WebPartHelpMode);
2452 case ExportTypeChromeState:
2453 return typeof(PartChromeState);
2454 case ExportTypeChromeType:
2455 return typeof(PartChromeType);
2456 case ExportTypeExportMode:
2457 return typeof(WebPartExportMode);
2458 case ExportTypeObject:
2459 return typeof(object);
2461 return WebPartUtil.DeserializeType(name, false);
2465 private static string GetExportName(Type type) {
2466 if (type == typeof(string)) {
2467 return ExportTypeString;
2469 else if (type == typeof(int)) {
2470 return ExportTypeInt;
2472 else if (type == typeof(bool)) {
2473 return ExportTypeBool;
2475 else if (type == typeof(double)) {
2476 return ExportTypeDouble;
2478 else if (type == typeof(Single)) {
2479 return ExportTypeSingle;
2481 else if (type == typeof(DateTime)) {
2482 return ExportTypeDateTime;
2484 else if (type == typeof(Color)) {
2485 return ExportTypeColor;
2487 else if (type == typeof(Unit)) {
2488 return ExportTypeUnit;
2490 else if (type == typeof(FontSize)) {
2491 return ExportTypeFontSize;
2493 else if (type == typeof(ContentDirection)) {
2494 return ExportTypeDirection;
2496 else if (type == typeof(WebPartHelpMode)) {
2497 return ExportTypeHelpMode;
2499 else if (type == typeof(PartChromeState)) {
2500 return ExportTypeChromeState;
2502 else if (type == typeof(PartChromeType)) {
2503 return ExportTypeChromeType;
2505 else if (type == typeof(WebPartExportMode)) {
2506 return ExportTypeExportMode;
2508 else if (type == typeof(object)) {
2509 return ExportTypeObject;
2512 return type.AssemblyQualifiedName;
2517 /// Used by the page developer to get a reference to the WebPart that contains a control
2518 /// placed in a WebPartZone. Returns null if the control is not inside a WebPart.
2520 public GenericWebPart GetGenericWebPart(Control control) {
2521 if (control == null) {
2522 throw new ArgumentNullException("control");
2525 // PERF: First check the parent of the control, before looping through all GenericWebParts
2526 Control parent = control.Parent;
2527 GenericWebPart genericParent = parent as GenericWebPart;
2528 if (genericParent != null && genericParent.ChildControl == control) {
2529 return genericParent;
2532 foreach (WebPart part in Controls) {
2533 GenericWebPart genericPart = part as GenericWebPart;
2534 if (genericPart != null && genericPart.ChildControl == control) {
2543 internal ProviderConnectionPoint GetProviderConnectionPoint(WebPart webPart, string connectionPointID) {
2544 ProviderConnectionPointCollection points = GetProviderConnectionPoints(webPart);
2545 if (points != null && points.Count > 0) {
2546 return points[connectionPointID];
2553 public virtual ProviderConnectionPointCollection GetProviderConnectionPoints(WebPart webPart) {
2554 if (webPart == null) {
2555 throw new ArgumentNullException("webPart");
2557 // Do not check that Controls.Contains(webPart), since this may be called on a WebPart
2558 // outside of a Zone. Also, this method shouldn't really care whether the WebPart is
2559 // inside the WebPartManager.
2561 return GetProviderConnectionPoints(webPart.ToControl().GetType());
2564 private static ProviderConnectionPointCollection GetProviderConnectionPoints(Type type) {
2565 ICollection[] connectionPoints = GetConnectionPoints(type);
2566 return (ProviderConnectionPointCollection)connectionPoints[1];
2570 /// Returns the web parts that should currently be rendered by the zone. It is important that
2571 /// this method filter out any web parts that will not be rendered by the zone, otherwise
2572 /// the AddWebPart method will not work correctly (VSWhidbey 77719)
2574 internal WebPartCollection GetWebPartsForZone(WebPartZoneBase zone) {
2576 throw new ArgumentNullException("zone");
2578 if (_webPartZones.Contains(zone) == false) {
2579 throw new ArgumentException(SR.GetString(SR.WebPartManager_MustRegister), "zone");
2582 IList allWebPartsForZone = GetAllWebPartsForZone(zone);
2583 WebPartCollection webParts = new WebPartCollection();
2585 if (allWebPartsForZone.Count > 0) {
2586 foreach (WebPart part in allWebPartsForZone) {
2587 if (ShouldRenderWebPartInZone(part, zone)) {
2597 /// If the WebPart is a consumer on the given connection point, returns the corresponding connection.
2598 /// Else, returns null.
2600 internal WebPartConnection GetConnectionForConsumer(WebPart consumer, ConsumerConnectionPoint connectionPoint) {
2601 ConsumerConnectionPoint actualConnectionPoint = connectionPoint;
2603 if (connectionPoint == null) {
2604 actualConnectionPoint = GetConsumerConnectionPoint(consumer, null);
2607 // PERF: Use the StaticConnections and DynamicConnections collections separately, instead
2608 // of using the Connections property which is created on every call.
2609 foreach (WebPartConnection connection in StaticConnections) {
2610 if (!Internals.ConnectionDeleted(connection) && connection.Consumer == consumer) {
2611 ConsumerConnectionPoint c =
2612 GetConsumerConnectionPoint(consumer, connection.ConsumerConnectionPointID);
2613 if (c == actualConnectionPoint) {
2619 foreach (WebPartConnection connection in DynamicConnections) {
2620 if (!Internals.ConnectionDeleted(connection) && connection.Consumer == consumer) {
2621 ConsumerConnectionPoint c =
2622 GetConsumerConnectionPoint(consumer, connection.ConsumerConnectionPointID);
2623 if (c == actualConnectionPoint) {
2633 /// If the WebPart is a provider on the given connection point, returns the corresponding connection.
2634 /// Else, returns null.
2636 internal WebPartConnection GetConnectionForProvider(WebPart provider, ProviderConnectionPoint connectionPoint) {
2637 ProviderConnectionPoint actualConnectionPoint = connectionPoint;
2638 if (connectionPoint == null) {
2639 actualConnectionPoint = GetProviderConnectionPoint(provider, null);
2642 // PERF: Use the StaticConnections and DynamicConnections collections separately, instead
2643 // of using the Connections property which is created on every call.
2644 foreach (WebPartConnection connection in StaticConnections) {
2645 if (!Internals.ConnectionDeleted(connection) && connection.Provider == provider) {
2646 ProviderConnectionPoint c =
2647 GetProviderConnectionPoint(provider, connection.ProviderConnectionPointID);
2648 if (c == actualConnectionPoint) {
2654 foreach (WebPartConnection connection in DynamicConnections) {
2655 if (!Internals.ConnectionDeleted(connection) && connection.Provider == provider) {
2656 ProviderConnectionPoint c =
2657 GetProviderConnectionPoint(provider, connection.ProviderConnectionPointID);
2658 if (c == actualConnectionPoint) {
2667 private static void ImportReadTo(XmlReader reader, string elementToFind) {
2668 while (reader.Name != elementToFind) {
2669 if (!reader.Read()) {
2670 throw new XmlException();
2675 private static void ImportReadTo(XmlReader reader, string elementToFindA, string elementToFindB) {
2676 while (reader.Name != elementToFindA && reader.Name != elementToFindB) {
2677 if (!reader.Read()) {
2678 throw new XmlException();
2683 private static void ImportSkipTo(XmlReader reader, string elementToFind) {
2684 while (reader.Name != elementToFind) {
2687 throw new XmlException();
2693 /// Never throws except for null arguments. Returns an error message in the out parameter instead.
2694 /// [Microsoft] I investigated whether this could be refactored to share common code with
2695 /// LoadDynamicWebPart(), but it seems the methods are too different.
2697 public virtual WebPart ImportWebPart(XmlReader reader, out string errorMessage) {
2698 Personalization.EnsureEnabled(/* ensureModifiable */ true);
2700 if (reader == null) {
2701 throw new ArgumentNullException("reader");
2704 bool permitOnly = false;
2706 if (UsePermitOnly) {
2707 MinimalPermissionSet.PermitOnly();
2710 string importErrorMessage = string.Empty;
2711 // Extra try-catch block to prevent elevation of privilege attack via exception filter
2714 // Get to the metadata
2715 reader.MoveToContent();
2716 reader.ReadStartElement(ExportRootElement);
2717 ImportSkipTo(reader, ExportPartElement);
2718 // Check the version on the webPart element
2719 string version = reader.GetAttribute(ExportPartNamespaceAttribute);
2720 if (String.IsNullOrEmpty(version)) {
2721 errorMessage = SR.GetString(SR.WebPart_ImportErrorNoVersion);
2724 if (!String.Equals(version, ExportPartNamespaceValue, StringComparison.OrdinalIgnoreCase)) {
2725 errorMessage = SR.GetString(SR.WebPart_ImportErrorInvalidVersion);
2728 ImportReadTo(reader, ExportMetaDataElement);
2729 reader.ReadStartElement(ExportMetaDataElement);
2730 // Get the type name
2731 string partTypeName = null;
2732 string userControlTypeName = null;
2733 ImportSkipTo(reader, ExportTypeElement);
2734 partTypeName = reader.GetAttribute(ExportTypeNameAttribute);
2735 userControlTypeName = reader.GetAttribute(ExportUserControlSrcAttribute);
2736 // Get the error message to display if unsuccessful to load the type
2737 ImportSkipTo(reader, ExportErrorMessageElement);
2738 importErrorMessage = reader.ReadElementString();
2739 // Get a type object from the type name
2741 WebPart part = null;
2742 Control childControl = null;
2745 // If we are in shared scope, we are importing a shared WebPart
2746 bool isShared = (Personalization.Scope == PersonalizationScope.Shared);
2748 if (!String.IsNullOrEmpty(partTypeName)) {
2750 if (UsePermitOnly) {
2751 CodeAccessPermission.RevertPermitOnly();
2753 MediumPermissionSet.PermitOnly();
2757 partType = WebPartUtil.DeserializeType(partTypeName, true);
2759 if (UsePermitOnly) {
2760 CodeAccessPermission.RevertPermitOnly();
2762 MinimalPermissionSet.PermitOnly();
2766 // First check if the type is authorized
2767 if (!IsAuthorized(partType, null, null, isShared)) {
2768 errorMessage = SR.GetString(SR.WebPartManager_ForbiddenType);
2771 // If the type is not a webpart, create a generic Web Part
2772 if (!partType.IsSubclassOf(typeof(WebPart))) {
2773 if (!partType.IsSubclassOf(typeof(Control))) {
2774 // We only allow for Controls (VSWhidbey 428511)
2775 errorMessage = SR.GetString(SR.WebPartManager_TypeMustDeriveFromControl);
2778 // Create an instance of the object
2779 childControl = (Control)(Internals.CreateObjectFromType(partType));
2780 childControl.ID = CreateDynamicWebPartID(partType);
2781 part = CreateWebPart(childControl);
2784 // Create an instance of the object
2785 part = (WebPart)(Internals.CreateObjectFromType(partType));
2789 // Instantiate a user control in a generic web part
2791 // Check if the path is authorized
2792 if (!IsAuthorized(typeof(UserControl), userControlTypeName, null, isShared)) {
2793 errorMessage = SR.GetString(SR.WebPartManager_ForbiddenType);
2797 if (UsePermitOnly) {
2798 CodeAccessPermission.RevertPermitOnly();
2801 childControl = Page.LoadControl(userControlTypeName);
2802 partType = childControl.GetType();
2803 if (UsePermitOnly) {
2804 MinimalPermissionSet.PermitOnly();
2807 childControl.ID = CreateDynamicWebPartID(partType);
2808 part = CreateWebPart(childControl);
2812 if (!String.IsNullOrEmpty(importErrorMessage)) {
2813 errorMessage = importErrorMessage;
2816 errorMessage = SR.GetString(SR.WebPartManager_ErrorLoadingWebPartType);
2821 // Set default error message for all subsequent errors
2822 if (String.IsNullOrEmpty(importErrorMessage)) {
2823 importErrorMessage = SR.GetString(SR.WebPart_DefaultImportErrorMessage);
2826 ImportSkipTo(reader, ExportDataElement);
2827 reader.ReadStartElement(ExportDataElement);
2828 ImportSkipTo(reader, ExportPropertiesElement);
2829 if (!reader.IsEmptyElement) {
2830 reader.ReadStartElement(ExportPropertiesElement);
2831 // Special-case IPersonalizable controls
2832 // ImportFromReader will set the right permission set when appropriate, reverting before we call
2833 if (UsePermitOnly) {
2834 CodeAccessPermission.RevertPermitOnly();
2837 ImportIPersonalizable(reader, (childControl != null ? childControl : part));
2838 if (UsePermitOnly) {
2839 MinimalPermissionSet.PermitOnly();
2843 // Set property values from XML description
2844 IDictionary personalizableProperties;
2845 if (childControl != null) {
2846 if (!reader.IsEmptyElement) {
2847 // Get the collection of personalizable properties for the child control
2848 personalizableProperties = PersonalizableAttribute.GetPersonalizablePropertyEntries(partType);
2850 // Copied from below. We must also execute this code when parsing the ChildControl
2851 // IPersonalizable and Personalizable properties.
2852 while (reader.Name != ExportPropertyElement) {
2855 errorMessage = null;
2860 // ImportFromReader will set the right permission set when appropriate, reverting before we call
2861 if (UsePermitOnly) {
2862 CodeAccessPermission.RevertPermitOnly();
2865 ImportFromReader(personalizableProperties, childControl, reader);
2866 if (UsePermitOnly) {
2867 MinimalPermissionSet.PermitOnly();
2871 // And then for the generic WebPart
2872 ImportSkipTo(reader, ExportGenericPartPropertiesElement);
2873 reader.ReadStartElement(ExportGenericPartPropertiesElement);
2874 // ImportFromReader will set the right permission set when appropriate, reverting before we call
2875 if (UsePermitOnly) {
2876 CodeAccessPermission.RevertPermitOnly();
2879 ImportIPersonalizable(reader, part);
2880 if (UsePermitOnly) {
2881 MinimalPermissionSet.PermitOnly();
2884 personalizableProperties = PersonalizableAttribute.GetPersonalizablePropertyEntries(part.GetType());
2887 // Get the collection of personalizable properties
2888 personalizableProperties = PersonalizableAttribute.GetPersonalizablePropertyEntries(partType);
2891 while (reader.Name != ExportPropertyElement) {
2894 errorMessage = null;
2899 // ImportFromReader will set the right permission set when appropriate, reverting before we call
2900 if (UsePermitOnly) {
2901 CodeAccessPermission.RevertPermitOnly();
2904 ImportFromReader(personalizableProperties, part, reader);
2905 if (UsePermitOnly) {
2906 MinimalPermissionSet.PermitOnly();
2909 errorMessage = null;
2910 // Return imported part
2913 catch (XmlException) {
2914 errorMessage = SR.GetString(SR.WebPartManager_ImportInvalidFormat);
2917 catch (Exception e) {
2918 if ((Context != null) && (Context.IsCustomErrorEnabled)) {
2919 errorMessage = (importErrorMessage.Length != 0) ?
2920 importErrorMessage :
2921 SR.GetString(SR.WebPart_DefaultImportErrorMessage);
2924 errorMessage = e.Message;
2930 // revert if you're not just exiting the stack frame anyway
2931 CodeAccessPermission.RevertPermitOnly();
2940 private void ImportIPersonalizable(XmlReader reader, Control control) {
2941 if (control is IPersonalizable) {
2942 // The control may implement IPersonalizable, but the .WebPart file may not contain
2943 // an "ipersonalizable" element. The WebPart may have returned no data from its
2944 // IPersonalizable.Save() method, or the WebPart may have been recently changed to
2945 // implement IPersonalizable. This are valid scenarios, so we should not require
2946 // the XML to contain the "ipersonalizable" element. (VSWhidbey 499016)
2948 // Read to the next element that is either "property" or "ipersonalizable".
2949 ImportReadTo(reader, ExportIPersonalizableElement, ExportPropertyElement);
2951 // If the next element is "ipersonalizable", then we import the IPersonalizable data.
2952 // Else, we do nothing, and the current "property" element will be imported as a standard
2953 // personalizable property.
2954 if (reader.Name == ExportIPersonalizableElement) {
2955 // Create a dictionary from the XML description
2956 reader.ReadStartElement(ExportIPersonalizableElement);
2957 ImportFromReader(null, control, reader);
2962 private void ImportFromReader(IDictionary personalizableProperties,
2966 Debug.Assert(target != null);
2968 ImportReadTo(reader, ExportPropertyElement);
2970 bool permitOnly = false;
2972 if (UsePermitOnly) {
2973 MinimalPermissionSet.PermitOnly();
2979 IDictionary properties;
2980 if (personalizableProperties != null) {
2981 properties = new HybridDictionary();
2984 properties = new PersonalizationDictionary();
2986 // Set properties from the xml document
2987 while (reader.Name == ExportPropertyElement) {
2988 // Get the name of the property
2989 string propertyName = reader.GetAttribute(ExportPropertyNameAttribute);
2990 string typeName = reader.GetAttribute(ExportPropertyTypeAttribute);
2991 string scope = reader.GetAttribute(ExportPropertyScopeAttribute);
2992 bool isNull = String.Equals(
2993 reader.GetAttribute(ExportPropertyNullAttribute),
2995 StringComparison.OrdinalIgnoreCase);
2997 // Do not import Zone information or AuthorizationFilter or custom data
2998 if (propertyName == AuthorizationFilterName ||
2999 propertyName == ZoneIDName ||
3000 propertyName == ZoneIndexName) {
3002 reader.ReadElementString();
3003 if (!reader.Read()) {
3004 throw new XmlException();
3008 string valString = reader.ReadElementString();
3010 bool valueComputed = false;
3011 PropertyInfo pi = null;
3012 if (personalizableProperties != null) {
3013 // Get the relevant personalizable property on the target (no need to check the property is personalizable)
3014 PersonalizablePropertyEntry entry = (PersonalizablePropertyEntry)(personalizableProperties[propertyName]);
3015 if (entry != null) {
3016 pi = entry.PropertyInfo;
3017 Debug.Assert(pi != null);
3018 // If the property is a url, validate protocol (VSWhidbey 290418)
3019 UrlPropertyAttribute urlAttr = Attribute.GetCustomAttribute(pi, typeof(UrlPropertyAttribute), true) as UrlPropertyAttribute;
3020 if (urlAttr != null && CrossSiteScriptingValidation.IsDangerousUrl(valString)) {
3021 throw new InvalidDataException(SR.GetString(SR.WebPart_BadUrl, valString));
3027 if (!String.IsNullOrEmpty(typeName)) {
3028 if (UsePermitOnly) {
3029 // Need medium trust to call BuildManager.GetType()
3030 CodeAccessPermission.RevertPermitOnly();
3032 MediumPermissionSet.PermitOnly();
3035 type = GetExportType(typeName);
3037 if (UsePermitOnly) {
3038 CodeAccessPermission.RevertPermitOnly();
3040 MinimalPermissionSet.PermitOnly();
3045 if ((pi != null) && ((pi.PropertyType == type) || (type == null))) {
3046 // Look at the target property
3047 // See if the property itself has a type converter associated with it
3048 TypeConverterAttribute attr = Attribute.GetCustomAttribute(pi, typeof(TypeConverterAttribute), true) as TypeConverterAttribute;
3050 if (UsePermitOnly) {
3051 // Need medium trust to call BuildManager.GetType()
3052 CodeAccessPermission.RevertPermitOnly();
3054 MediumPermissionSet.PermitOnly();
3058 Type converterType = WebPartUtil.DeserializeType(attr.ConverterTypeName, false);
3060 if (UsePermitOnly) {
3061 CodeAccessPermission.RevertPermitOnly();
3063 MinimalPermissionSet.PermitOnly();
3067 // SECURITY: Check that the type is a subclass of TypeConverter before instantiating.
3068 if (converterType != null && converterType.IsSubclassOf(typeof(TypeConverter))) {
3069 TypeConverter converter = (TypeConverter)(Internals.CreateObjectFromType(converterType));
3070 if (Util.CanConvertToFrom(converter, typeof(string))) {
3072 val = converter.ConvertFromInvariantString(valString);
3074 valueComputed = true;
3078 // Then, look at the converters on the property type
3079 if (!valueComputed) {
3080 // Use the type converter associated with the type itself
3081 TypeConverter converter = TypeDescriptor.GetConverter(pi.PropertyType);
3082 if (Util.CanConvertToFrom(converter, typeof(string))) {
3084 val = converter.ConvertFromInvariantString(valString);
3086 valueComputed = true;
3087 // Not importing anything else for security reasons
3091 // finally, use the XML-specified type
3092 if (!valueComputed && (type != null)) {
3093 // Look at the XML-declared type
3094 if (type == typeof(string)) {
3098 valueComputed = true;
3101 TypeConverter typeConverter = TypeDescriptor.GetConverter(type);
3102 if (Util.CanConvertToFrom(typeConverter, typeof(string))) {
3104 val = typeConverter.ConvertFromInvariantString(valString);
3106 valueComputed = true;
3111 // Always want to import a null IPersonalizable value, since we will never have a type
3112 // converter for the value. However, we should not import a null Personalizable value
3113 // unless the PropertyInfo had a type converter, since the property may be a value type
3114 // that cannot accept null as a value. (VSWhidbey 537895)
3115 if (isNull && personalizableProperties == null) {
3116 valueComputed = true;
3119 // Now we should have a value (val)
3120 if (valueComputed) {
3121 if (personalizableProperties != null) {
3122 properties.Add(propertyName, val);
3126 PersonalizationScope personalizationScope =
3127 String.Equals(scope, PersonalizationScope.Shared.ToString(), StringComparison.OrdinalIgnoreCase) ?
3128 PersonalizationScope.Shared : PersonalizationScope.User;
3129 properties.Add(propertyName, new PersonalizationEntry(val, personalizationScope));
3133 throw new HttpException(SR.GetString(SR.WebPartManager_ImportInvalidData, propertyName));
3136 while (reader.Name != ExportPropertyElement) {
3138 (reader.Name == ExportGenericPartPropertiesElement) ||
3139 (reader.Name == ExportPropertiesElement) ||
3140 ((reader.Name == ExportIPersonalizableElement) && (reader.NodeType == XmlNodeType.EndElement))) {
3147 if (personalizableProperties != null) {
3148 IDictionary unused = BlobPersonalizationState.SetPersonalizedProperties(target, properties);
3149 if ((unused != null) && (unused.Count > 0)) {
3150 IVersioningPersonalizable versioningTarget = target as IVersioningPersonalizable;
3151 if (versioningTarget != null) {
3152 versioningTarget.Load(unused);
3157 Debug.Assert(target is IPersonalizable);
3158 ((IPersonalizable)target).Load((PersonalizationDictionary)properties);
3163 // revert if you're not just exiting the stack frame anyway
3164 CodeAccessPermission.RevertPermitOnly();
3173 public virtual bool IsAuthorized(Type type, string path, string authorizationFilter, bool isShared) {
3175 throw new ArgumentNullException("type");
3178 if (type == typeof(UserControl)) {
3179 if (String.IsNullOrEmpty(path)) {
3180 throw new ArgumentException(SR.GetString(SR.WebPartManager_PathCannotBeEmpty));
3184 if (!String.IsNullOrEmpty(path)) {
3185 throw new ArgumentException(SR.GetString(SR.WebPartManager_PathMustBeEmpty, path));
3189 WebPartAuthorizationEventArgs auth = new WebPartAuthorizationEventArgs(type, path, authorizationFilter, isShared);
3190 OnAuthorizeWebPart(auth);
3191 return auth.IsAuthorized;
3194 public bool IsAuthorized(WebPart webPart) {
3195 if (webPart == null) {
3196 throw new ArgumentNullException("webPart");
3199 // Do not check that Controls.Contains(webPart), since this will be called on a WebPart
3200 // before it is added to the Controls collection.
3202 // Calculate authorizationFilter from property value and personalization data
3203 string authorizationFilter = webPart.AuthorizationFilter;
3205 // webPart.ID will be null for imported WebParts. Also, a user may want to call
3206 // this method on a WebPart before it has an ID.
3207 string webPartID = webPart.ID;
3208 if (!String.IsNullOrEmpty(webPartID) && Personalization.IsEnabled) {
3209 string personalizedAuthorizationFilter = Personalization.GetAuthorizationFilter(webPart.ID);
3210 if (personalizedAuthorizationFilter != null) {
3211 authorizationFilter = personalizedAuthorizationFilter;
3215 GenericWebPart genericWebPart = webPart as GenericWebPart;
3216 if (genericWebPart != null) {
3217 Type childType = null;
3218 string childPath = null;
3220 Control childControl = genericWebPart.ChildControl;
3221 UserControl childUserControl = childControl as UserControl;
3222 if (childUserControl != null) {
3223 childType = typeof(UserControl);
3224 childPath = childUserControl.AppRelativeVirtualPath;
3227 childType = childControl.GetType();
3230 // Only authorize the type/path of the child control
3231 // Don't need to authorize the GenericWebPart as well
3232 return IsAuthorized(childType, childPath, authorizationFilter, webPart.IsShared);
3235 return IsAuthorized(webPart.GetType(), null, authorizationFilter, webPart.IsShared);
3239 internal bool IsConsumerConnected(WebPart consumer, ConsumerConnectionPoint connectionPoint) {
3240 return (GetConnectionForConsumer(consumer, connectionPoint) != null);
3243 internal bool IsProviderConnected(WebPart provider, ProviderConnectionPoint connectionPoint) {
3244 return (GetConnectionForProvider(provider, connectionPoint) != null);
3248 /// Loads the control state for those properties that should persist across postbacks
3249 /// even when EnableViewState=false.
3251 protected internal override void LoadControlState(object savedState) {
3252 if (savedState == null) {
3253 base.LoadControlState(null);
3256 object[] myState = (object[])savedState;
3257 if (myState.Length != controlStateArrayLength) {
3258 throw new ArgumentException(SR.GetString(SR.Invalid_ControlState));
3261 base.LoadControlState(myState[baseIndex]);
3265 if (myState[selectedWebPartIndex] != null) {
3266 // All dynamic parts must be loaded before this point, in case a dynamic part is the
3268 WebPart selectedWebPart = WebParts[(string)myState[selectedWebPartIndex]];
3269 if (selectedWebPart == null || selectedWebPart.IsClosed) {
3270 // The SelectedWebPart was either closed or deleted between requests.
3271 // Raise the changed event, since the SelectedWebPart was not null on the previous request.
3272 SetSelectedWebPart(null);
3273 OnSelectedWebPartChanged(new WebPartEventArgs(null));
3276 SetSelectedWebPart(selectedWebPart);
3279 if (myState[displayModeIndex] != null) {
3280 string modeName = (string)myState[displayModeIndex];
3282 WebPartDisplayMode restoredDisplayMode = SupportedDisplayModes[modeName];
3283 if (!restoredDisplayMode.IsEnabled(this)) {
3287 if (restoredDisplayMode == null) {
3288 _displayMode = BrowseDisplayMode;
3289 OnDisplayModeChanged(new WebPartDisplayModeEventArgs(null));
3292 _displayMode = restoredDisplayMode;
3298 protected virtual void LoadCustomPersonalizationState(PersonalizationDictionary state) {
3299 // The state must be loaded after the Static Connections and WebParts have been added
3300 // to the WebPartManager (after the WebPartZone's and ProxyWebPartManager's Init methods)
3301 _personalizationState = state;
3304 private void LoadDynamicConnections(PersonalizationEntry entry) {
3305 if (entry != null) {
3306 object[] dynamicConnectionState = (object[])entry.Value;
3307 if (dynamicConnectionState != null) {
3308 Debug.Assert(dynamicConnectionState.Length % 7 == 0);
3309 for (int i = 0; i < dynamicConnectionState.Length; i += 7) {
3310 string ID = (string)dynamicConnectionState[i];
3311 string consumerID = (string)dynamicConnectionState[i + 1];
3312 string consumerConnectionPointID = (string)dynamicConnectionState[i + 2];
3313 string providerID = (string)dynamicConnectionState[i + 3];
3314 string providerConnectionPointID = (string)dynamicConnectionState[i + 4];
3316 // Add a new connection to the collection
3317 WebPartConnection connection = new WebPartConnection();
3319 connection.ConsumerID = consumerID;
3320 connection.ConsumerConnectionPointID = consumerConnectionPointID;
3321 connection.ProviderID = providerID;
3322 connection.ProviderConnectionPointID = providerConnectionPointID;
3323 Internals.SetIsShared(connection, (entry.Scope == PersonalizationScope.Shared));
3324 Internals.SetIsStatic(connection, false);
3326 Type type = dynamicConnectionState[i + 5] as Type;
3328 // SECURITY: Only instantiate type if it is a subclass of WebPartTransformer
3329 if (type.IsSubclassOf(typeof(WebPartTransformer))) {
3330 object configuration = dynamicConnectionState[i + 6];
3331 WebPartTransformer transformer = (WebPartTransformer)Internals.CreateObjectFromType(type);
3332 Internals.LoadConfigurationState(transformer, configuration);
3333 Internals.SetTransformer(connection, transformer);
3336 throw new InvalidOperationException(SR.GetString(SR.WebPartTransformerAttribute_NotTransformer, type.Name));
3340 DynamicConnections.Add(connection);
3346 private void LoadDynamicWebPart(string id, string typeName, string path, string genericWebPartID, bool isShared) {
3347 WebPart dynamicWebPart = null;
3348 Type type = WebPartUtil.DeserializeType(typeName, false);
3350 string errorMessage;
3351 if (Context != null && Context.IsCustomErrorEnabled) {
3352 errorMessage = SR.GetString(SR.WebPartManager_ErrorLoadingWebPartType);
3355 errorMessage = SR.GetString(SR.Invalid_type, typeName);
3357 dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage);
3359 else if (type.IsSubclassOf(typeof(WebPart))) {
3360 string authorizationFilter = Personalization.GetAuthorizationFilter(id);
3361 if (IsAuthorized(type, null, authorizationFilter, isShared)) {
3363 dynamicWebPart = (WebPart)Internals.CreateObjectFromType(type);
3364 dynamicWebPart.ID = id;
3367 // If custom errors are enabled, we do not want to render the type name to the browser.
3368 // (VSWhidbey 381646)
3369 string errorMessage;
3370 if (Context != null && Context.IsCustomErrorEnabled) {
3371 errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstance);
3374 errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstanceWithType, typeName);
3376 dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage);
3380 dynamicWebPart = new UnauthorizedWebPart(id, typeName, path, genericWebPartID);
3383 else if (type.IsSubclassOf(typeof(Control))) {
3384 string authorizationFilter = Personalization.GetAuthorizationFilter(genericWebPartID);
3385 if (IsAuthorized(type, path, authorizationFilter, isShared)) {
3386 Control childControl = null;
3388 if (!String.IsNullOrEmpty(path)) {
3389 Debug.Assert(type == typeof(UserControl));
3390 childControl = Page.LoadControl(path);
3393 childControl = (Control)Internals.CreateObjectFromType(type);
3395 childControl.ID = id;
3397 dynamicWebPart = CreateWebPart(childControl);
3398 dynamicWebPart.ID = genericWebPartID;
3401 string errorMessage;
3402 if (childControl == null && String.IsNullOrEmpty(path)) {
3403 if (Context != null && Context.IsCustomErrorEnabled) {
3404 errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstance);
3407 errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstanceWithType, typeName);
3410 else if (childControl == null) {
3411 if (Context != null && Context.IsCustomErrorEnabled) {
3412 errorMessage = SR.GetString(SR.WebPartManager_InvalidPath);
3415 errorMessage = SR.GetString(SR.WebPartManager_InvalidPathWithPath, path);
3419 errorMessage = SR.GetString(SR.WebPartManager_CantCreateGeneric);
3421 dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage);
3425 dynamicWebPart = new UnauthorizedWebPart(id, typeName, path, genericWebPartID);
3429 // Type is not a subclass of Control. For security, do not even instantiate
3430 // the type (VSWhidbey 428511).
3431 string errorMessage;
3432 if (Context != null && Context.IsCustomErrorEnabled) {
3433 errorMessage = SR.GetString(SR.WebPartManager_TypeMustDeriveFromControl);
3436 errorMessage = SR.GetString(SR.WebPartManager_TypeMustDeriveFromControlWithType, typeName);
3438 dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage);
3441 Debug.Assert(dynamicWebPart != null);
3442 Internals.SetIsStatic(dynamicWebPart, false);
3443 Internals.SetIsShared(dynamicWebPart, isShared);
3444 Internals.AddWebPart(dynamicWebPart);
3447 private void LoadDynamicWebParts(PersonalizationEntry entry) {
3448 if (entry != null) {
3449 object[] dynamicWebPartState = (object[])entry.Value;
3450 if (dynamicWebPartState != null) {
3451 Debug.Assert(dynamicWebPartState.Length % 4 == 0);
3452 bool isShared = (entry.Scope == PersonalizationScope.Shared);
3455 for (int i = 0; i < dynamicWebPartState.Length; i += 4) {
3456 string id = (string)dynamicWebPartState[i];
3457 string typeName = (string)dynamicWebPartState[i + 1];
3458 string path = (string)dynamicWebPartState[i + 2];
3459 string genericWebPartID = (string)dynamicWebPartState[i + 3];
3461 LoadDynamicWebPart(id, typeName, path, genericWebPartID, isShared);
3467 private void LoadDeletedConnectionState(PersonalizationEntry entry) {
3468 if (entry != null) {
3469 string[] deletedConnections = (string[])entry.Value;
3470 if (deletedConnections != null) {
3471 for (int i=0; i < deletedConnections.Length; i++) {
3472 string idToDelete = deletedConnections[i];
3473 WebPartConnection connectionToDelete = null;
3475 foreach (WebPartConnection connection in StaticConnections) {
3476 if (String.Equals(connection.ID, idToDelete, StringComparison.OrdinalIgnoreCase)) {
3477 connectionToDelete = connection;
3481 if (connectionToDelete == null) {
3482 foreach (WebPartConnection connection in DynamicConnections) {
3483 if (String.Equals(connection.ID, idToDelete, StringComparison.OrdinalIgnoreCase)) {
3484 connectionToDelete = connection;
3490 if (connectionToDelete != null) {
3491 // Only shared connections can be deleted
3492 Debug.Assert(connectionToDelete.IsShared);
3494 // In shared scope, only static connections should be deleted
3495 // In user scope, static and dynamic connections can be deleted
3496 Debug.Assert(connectionToDelete.IsStatic || entry.Scope == PersonalizationScope.User);
3498 Internals.DeleteConnection(connectionToDelete);
3501 // Some of the personalization data is invalid, so we should mark ourselves
3502 // as dirty so the data will be re-saved, and the invalid data will be removed.
3503 _hasDataChanged = true;
3511 /// Sets the ZoneID, ZoneIndex, and IsClosed properties on the WebParts. The state
3512 /// was loaded from personalization.
3514 private void LoadWebPartState(PersonalizationEntry entry) {
3515 if (entry != null) {
3516 object[] webPartState = (object[])entry.Value;
3517 if (webPartState != null) {
3518 Debug.Assert(webPartState.Length % 4 == 0);
3519 for (int i=0; i < webPartState.Length; i += 4) {
3520 string id = (string)webPartState[i];
3521 string zoneID = (string)webPartState[i + 1];
3522 int zoneIndex = (int)webPartState[i + 2];
3523 bool isClosed = (bool)webPartState[i + 3];
3525 WebPart part = (WebPart)FindControl(id);
3527 Internals.SetZoneID(part, zoneID);
3528 Internals.SetZoneIndex(part, zoneIndex);
3531 Internals.SetIsClosed(part, isClosed);
3534 // Some of the personalization data is invalid, so we should mark ourselves
3535 // as dirty so the data will be re-saved, and the invalid data will be removed.
3536 _hasDataChanged = true;
3545 public virtual void MoveWebPart(WebPart webPart, WebPartZoneBase zone, int zoneIndex) {
3546 Personalization.EnsureEnabled(/* ensureModifiable */ true);
3548 if (webPart == null) {
3549 throw new ArgumentNullException("webPart");
3551 if (!Controls.Contains(webPart)) {
3552 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
3555 throw new ArgumentNullException("zone");
3557 if (_webPartZones.Contains(zone) == false) {
3558 throw new ArgumentException(SR.GetString(SR.WebPartManager_MustRegister), "zone");
3560 if (zoneIndex < 0) {
3561 throw new ArgumentOutOfRangeException("zoneIndex");
3563 if (webPart.Zone == null || webPart.IsClosed) {
3564 throw new ArgumentException(SR.GetString(SR.WebPartManager_MustBeInZone), "webPart");
3567 // Return immediately if moving part to its current location
3568 if ((webPart.Zone == zone) && (webPart.ZoneIndex == zoneIndex)) {
3572 WebPartMovingEventArgs e = new WebPartMovingEventArgs(webPart, zone, zoneIndex);
3574 if (_allowEventCancellation && e.Cancel) {
3578 RemoveWebPartFromZone(webPart);
3579 AddWebPartToZone(webPart, zone, zoneIndex);
3581 // Raise event at very end of Move method
3582 OnWebPartMoved(new WebPartEventArgs(webPart));
3585 CheckPartZoneIndexes(webPart.Zone);
3586 CheckPartZoneIndexes(zone);
3590 protected virtual void OnAuthorizeWebPart(WebPartAuthorizationEventArgs e) {
3591 WebPartAuthorizationEventHandler handler = (WebPartAuthorizationEventHandler)Events[AuthorizeWebPartEvent];
3592 if (handler != null) {
3597 protected virtual void OnConnectionsActivated(EventArgs e) {
3598 EventHandler handler = (EventHandler)Events[ConnectionsActivatedEvent];
3599 if (handler != null) {
3604 protected virtual void OnConnectionsActivating(EventArgs e) {
3605 EventHandler handler = (EventHandler)Events[ConnectionsActivatingEvent];
3606 if (handler != null) {
3611 protected virtual void OnDisplayModeChanged(WebPartDisplayModeEventArgs e) {
3612 WebPartDisplayModeEventHandler handler = (WebPartDisplayModeEventHandler)Events[DisplayModeChangedEvent];
3613 if (handler != null) {
3618 protected virtual void OnDisplayModeChanging(WebPartDisplayModeCancelEventArgs e) {
3619 WebPartDisplayModeCancelEventHandler handler = (WebPartDisplayModeCancelEventHandler)Events[DisplayModeChangingEvent];
3620 if (handler != null) {
3627 protected internal override void OnInit(EventArgs e) {
3633 WebPartManager existingInstance = (WebPartManager)page.Items[typeof(WebPartManager)];
3635 if (existingInstance != null) {
3636 Debug.Assert(existingInstance != this);
3637 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_OnlyOneInstance));
3640 page.Items[typeof(WebPartManager)] = this;
3642 page.InitComplete += new EventHandler(this.OnPageInitComplete);
3643 page.LoadComplete += new EventHandler(this.OnPageLoadComplete);
3644 page.SaveStateComplete += new EventHandler(this.OnPageSaveStateComplete);
3645 page.RegisterRequiresControlState(this);
3647 Personalization.LoadInternal();
3654 protected internal override void OnUnload(EventArgs e) {
3660 Debug.Assert(page != null);
3662 page.Items.Remove(typeof(WebPartManager));
3667 private void OnPageInitComplete(object sender, EventArgs e) {
3668 if (_personalizationState != null) {
3669 // These must be loaded after the Static Connections have been added to the WebPartManager
3670 // (after the ProxyWebPartManager's Init methods)
3671 LoadDynamicConnections(_personalizationState["DynamicConnectionsShared"]);
3672 LoadDynamicConnections(_personalizationState["DynamicConnectionsUser"]);
3673 LoadDeletedConnectionState(_personalizationState["DeletedConnectionsShared"]);
3674 LoadDeletedConnectionState(_personalizationState["DeletedConnectionsUser"]);
3676 // These must be loaded after the Static WebParts have been added to the WebPartManager
3677 // (after the WebPartZone's Init methods)
3678 LoadDynamicWebParts(_personalizationState["DynamicWebPartsShared"]);
3679 LoadDynamicWebParts(_personalizationState["DynamicWebPartsUser"]);
3680 LoadWebPartState(_personalizationState["WebPartStateShared"]);
3681 LoadWebPartState(_personalizationState["WebPartStateUser"]);
3684 _pageInitComplete = true;
3687 private void OnPageLoadComplete(object sender, EventArgs e) {
3689 CloseOrphanedParts();
3691 _allowCreateDisplayTitles = true;
3693 // Raise events outside of ActivateConnections() method, since the method is virtual
3694 OnConnectionsActivating(EventArgs.Empty);
3695 // Activate connections in Page.LoadComplete instead of WebPartManager.PreRender.
3696 // Additional connection types can be activated here, so this improves our compatibility. (VSWhidbey 266995)
3697 ActivateConnections();
3698 OnConnectionsActivated(EventArgs.Empty);
3701 private void OnPageSaveStateComplete(object sender, EventArgs e) {
3702 // NOTE: Ideally this would be done by overriding SaveViewState in
3703 // WebPartManager and WebPart to be symmetric with Personalization
3704 // loading which happens in TrackViewState.
3705 // However SaveViewState is not called when view state is disabled. Also,
3706 // we don't want to have everything register for the SaveStateComplete event,
3707 // because that creates more management issues for the event handler list.
3708 // We don't want to change how the Apply works either, because we'd have
3709 // to set up listeners for the Init event on every webpart.
3710 Personalization.ExtractPersonalizationState();
3711 foreach (WebPart webPart in Controls) {
3712 Personalization.ExtractPersonalizationState(webPart);
3715 Personalization.SaveInternal();
3718 protected internal override void OnPreRender(EventArgs e) {
3719 base.OnPreRender(e);
3722 Page.ClientScript.RegisterStartupScript(
3724 typeof(WebPartManager),
3725 ExportSensitiveDataWarningDeclaration,
3726 "var __wpmExportWarning='" + Util.QuoteJScriptString(ExportSensitiveDataWarning) + "';",
3729 Page.ClientScript.RegisterStartupScript(
3731 typeof(WebPartManager),
3732 CloseProviderWarningDeclaration,
3733 "var __wpmCloseProviderWarning='" + Util.QuoteJScriptString(CloseProviderWarning) + "';",
3736 Page.ClientScript.RegisterStartupScript(
3738 typeof(WebPartManager),
3739 DeleteWarningDeclaration,
3740 "var __wpmDeleteWarning='" + Util.QuoteJScriptString(DeleteWarning) + "';",
3743 _renderClientScript = CheckRenderClientScript();
3744 if (_renderClientScript) {
3747 Page.RegisterPostBackScript();
3749 RegisterClientScript();
3754 protected virtual void OnSelectedWebPartChanged(WebPartEventArgs e) {
3755 WebPartEventHandler handler = (WebPartEventHandler)Events[SelectedWebPartChangedEvent];
3756 if (handler != null) {
3761 protected virtual void OnSelectedWebPartChanging(WebPartCancelEventArgs e) {
3762 WebPartCancelEventHandler handler = (WebPartCancelEventHandler)Events[SelectedWebPartChangingEvent];
3763 if (handler != null) {
3768 protected virtual void OnWebPartAdded(WebPartEventArgs e) {
3769 WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartAddedEvent];
3770 if (handler != null) {
3775 protected virtual void OnWebPartAdding(WebPartAddingEventArgs e) {
3776 WebPartAddingEventHandler handler = (WebPartAddingEventHandler)Events[WebPartAddingEvent];
3777 if (handler != null) {
3782 protected virtual void OnWebPartClosed(WebPartEventArgs e) {
3783 WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartClosedEvent];
3784 if (handler != null) {
3789 protected virtual void OnWebPartClosing(WebPartCancelEventArgs e) {
3790 WebPartCancelEventHandler handler = (WebPartCancelEventHandler)Events[WebPartClosingEvent];
3791 if (handler != null) {
3797 protected virtual void OnWebPartDeleted(WebPartEventArgs e) {
3798 WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartDeletedEvent];
3799 if (handler != null) {
3804 protected virtual void OnWebPartDeleting(WebPartCancelEventArgs e) {
3805 WebPartCancelEventHandler handler = (WebPartCancelEventHandler)Events[WebPartDeletingEvent];
3806 if (handler != null) {
3811 protected virtual void OnWebPartMoved(WebPartEventArgs e) {
3812 WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartMovedEvent];
3813 if (handler != null) {
3818 protected virtual void OnWebPartMoving(WebPartMovingEventArgs e) {
3819 WebPartMovingEventHandler handler = (WebPartMovingEventHandler)Events[WebPartMovingEvent];
3820 if (handler != null) {
3825 protected virtual void OnWebPartsConnected(WebPartConnectionsEventArgs e) {
3826 WebPartConnectionsEventHandler handler = (WebPartConnectionsEventHandler)Events[WebPartsConnectedEvent];
3827 if (handler != null) {
3832 protected virtual void OnWebPartsConnecting(WebPartConnectionsCancelEventArgs e) {
3833 WebPartConnectionsCancelEventHandler handler = (WebPartConnectionsCancelEventHandler)Events[WebPartsConnectingEvent];
3834 if (handler != null) {
3839 protected virtual void OnWebPartsDisconnected(WebPartConnectionsEventArgs e) {
3840 WebPartConnectionsEventHandler handler = (WebPartConnectionsEventHandler)Events[WebPartsDisconnectedEvent];
3841 if (handler != null) {
3846 protected virtual void OnWebPartsDisconnecting(WebPartConnectionsCancelEventArgs e) {
3847 WebPartConnectionsCancelEventHandler handler = (WebPartConnectionsCancelEventHandler)Events[WebPartsDisconnectingEvent];
3848 if (handler != null) {
3853 protected virtual void RegisterClientScript() {
3854 Page.ClientScript.RegisterClientScriptResource(this, typeof(WebPartManager), "WebParts.js");
3856 bool allowPageDesign = DisplayMode.AllowPageDesign;
3858 string dragOverlayElementReference = "null";
3859 if (allowPageDesign) {
3860 dragOverlayElementReference = "document.getElementById('" + ClientID + "___Drag')";
3863 StringBuilder zoneCode = new StringBuilder(1024);
3864 foreach (WebPartZoneBase zone in _webPartZones) {
3865 string isVertical = (zone.LayoutOrientation == Orientation.Vertical) ? "true" : "false";
3867 string allowLayoutChange = "false";
3868 string dragHighlightColor = "black";
3869 if (allowPageDesign && zone.AllowLayoutChange) {
3870 allowLayoutChange = "true";
3871 dragHighlightColor = ColorTranslator.ToHtml(zone.DragHighlightColor);
3874 zoneCode.AppendFormat(CultureInfo.InvariantCulture, ZoneScript, zone.ClientID, zone.UniqueID, isVertical,
3875 allowLayoutChange, dragHighlightColor);
3877 WebPartCollection webParts = GetWebPartsForZone(zone);
3878 foreach (WebPart webPart in webParts) {
3879 string titleBarElementReference = "null";
3880 string allowMove = "false";
3881 if (allowPageDesign) {
3882 titleBarElementReference = "document.getElementById('" + webPart.TitleBarID + "')";
3883 if (webPart.AllowZoneChange) {
3887 zoneCode.AppendFormat(ZonePartScript, webPart.WholePartID, titleBarElementReference, allowMove);
3890 zoneCode.Append(ZoneEndScript);
3893 string startupScript = String.Format(CultureInfo.InvariantCulture,
3895 dragOverlayElementReference,
3896 (Personalization.Scope == PersonalizationScope.Shared ? "true" : "false"),
3897 zoneCode.ToString());
3898 Page.ClientScript.RegisterStartupScript(this, typeof(WebPartManager), String.Empty, startupScript, false);
3900 IScriptManager scriptManager = Page.ScriptManager;
3901 if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
3902 scriptManager.RegisterDispose(this, "WebPartManager_Dispose();");
3906 internal void RegisterZone(WebZone zone) {
3907 Debug.Assert(zone != null);
3909 if (_pageInitComplete) {
3910 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_RegisterTooLate));
3913 string zoneID = zone.ID;
3914 if (String.IsNullOrEmpty(zoneID)) {
3915 throw new ArgumentException(SR.GetString(SR.WebPartManager_NoZoneID), "zone");
3917 if (_zoneIDs.Contains(zoneID)) {
3918 throw new ArgumentException(SR.GetString(SR.WebPartManager_DuplicateZoneID, zoneID));
3920 _zoneIDs.Add(zoneID, zone);
3922 WebPartZoneBase webPartZone = zone as WebPartZoneBase;
3923 if (webPartZone != null) {
3924 if (_webPartZones.Contains(webPartZone)) {
3925 throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyRegistered), "zone");
3928 _webPartZones.Add(webPartZone);
3930 WebPartCollection initialWebParts = webPartZone.GetInitialWebParts();
3931 ((WebPartManagerControlCollection)Controls).AddWebPartsFromZone(webPartZone, initialWebParts);
3934 Debug.Assert(zone is ToolZone);
3935 ToolZone toolZone = (ToolZone)zone;
3937 WebPartDisplayModeCollection allDisplayModes = DisplayModes;
3938 WebPartDisplayModeCollection supportedDisplayModes = SupportedDisplayModes;
3939 foreach (WebPartDisplayMode displayMode in toolZone.AssociatedDisplayModes) {
3940 if (allDisplayModes.Contains(displayMode) && !supportedDisplayModes.Contains(displayMode)) {
3941 supportedDisplayModes.AddInternal(displayMode);
3948 /// Deletes the part from the dictionary mapping zones to parts.
3950 private void RemoveWebPartFromDictionary(WebPart webPart) {
3951 if (_partsForZone != null) {
3952 string zoneID = Internals.GetZoneID(webPart);
3953 if (!String.IsNullOrEmpty(zoneID)) {
3954 SortedList partsForZone = (SortedList)(_partsForZone[zoneID]);
3955 if (partsForZone != null) {
3956 partsForZone.Remove(webPart);
3962 // Called by WebPartManagerInternals
3963 internal void RemoveWebPart(WebPart webPart) {
3964 ((WebPartManagerControlCollection)Controls).RemoveWebPart(webPart);
3968 /// Removes a web part from its zone, and renumbers all the remaining parts sequentially.
3970 private void RemoveWebPartFromZone(WebPart webPart) {
3971 Debug.Assert(!webPart.IsClosed);
3973 WebPartZoneBase zone = webPart.Zone;
3974 Internals.SetIsClosed(webPart, true);
3975 _hasDataChanged = true;
3977 RemoveWebPartFromDictionary(webPart);
3982 IList parts = GetAllWebPartsForZone(zone);
3983 for (int i = 0; i < parts.Count; i++) {
3984 WebPart part = ((WebPart)parts[i]);
3985 Internals.SetZoneIndex(part, i);
3990 protected internal override void Render(HtmlTextWriter writer) {
3991 if (DisplayMode.AllowPageDesign) {
3992 string dragOverlayElementHtml = String.Format(CultureInfo.InvariantCulture, DragOverlayElementHtmlTemplate, ClientID);
3993 writer.WriteLine(dragOverlayElementHtml);
3998 /// Saves the control state for those properties that should persist across postbacks
3999 /// even when EnableViewState=false.
4001 protected internal override object SaveControlState() {
4002 object[] myState = new object[controlStateArrayLength];
4004 myState[baseIndex] = base.SaveControlState();
4005 if (SelectedWebPart != null) {
4006 myState[selectedWebPartIndex] = SelectedWebPart.ID;
4008 if (_displayMode != BrowseDisplayMode) {
4009 myState[displayModeIndex] = _displayMode.Name;
4012 for (int i=0; i < controlStateArrayLength; i++) {
4013 if (myState[i] != null) {
4018 // More performant to return null than an array of null values
4022 protected virtual void SaveCustomPersonalizationState(PersonalizationDictionary state) {
4023 PersonalizationScope scope = Personalization.Scope;
4025 int webPartsCount = Controls.Count;
4026 if (webPartsCount > 0) {
4027 object[] webPartState = new object[webPartsCount * 4];
4028 for (int i=0; i < webPartsCount; i++) {
4029 WebPart webPart = (WebPart)Controls[i];
4030 webPartState[4*i] = webPart.ID;
4031 webPartState[4*i + 1] = Internals.GetZoneID(webPart);
4032 webPartState[4*i + 2] = webPart.ZoneIndex;
4033 webPartState[4*i + 3] = webPart.IsClosed;
4035 if (scope == PersonalizationScope.Shared) {
4036 state["WebPartStateShared"] =
4037 new PersonalizationEntry(webPartState, PersonalizationScope.Shared);
4040 state["WebPartStateUser"] =
4041 new PersonalizationEntry(webPartState, PersonalizationScope.User);
4045 // Select only the dynamic WebParts that should be saved for this mode
4046 ArrayList dynamicWebParts = new ArrayList();
4047 foreach (WebPart webPart in Controls) {
4048 if (!webPart.IsStatic &&
4049 ((scope == PersonalizationScope.User && !webPart.IsShared) ||
4050 (scope == PersonalizationScope.Shared && webPart.IsShared))) {
4051 dynamicWebParts.Add(webPart);
4055 int dynamicWebPartsCount = dynamicWebParts.Count;
4056 if (dynamicWebPartsCount > 0) {
4057 // Use a 1-dimensional array for smallest storage space
4058 object[] dynamicWebPartState = new object[dynamicWebPartsCount * 4];
4059 for (int i = 0; i < dynamicWebPartsCount; i++) {
4060 WebPart webPart = (WebPart)dynamicWebParts[i];
4065 string genericWebPartID = null;
4066 ProxyWebPart proxyWebPart = webPart as ProxyWebPart;
4067 if (proxyWebPart != null) {
4068 id = proxyWebPart.OriginalID;
4069 typeName = proxyWebPart.OriginalTypeName;
4070 path = proxyWebPart.OriginalPath;
4071 genericWebPartID = proxyWebPart.GenericWebPartID;
4074 GenericWebPart genericWebPart = webPart as GenericWebPart;
4075 if (genericWebPart != null) {
4076 Control childControl = genericWebPart.ChildControl;
4077 UserControl userControl = childControl as UserControl;
4079 id = childControl.ID;
4080 if (userControl != null) {
4081 typeName = WebPartUtil.SerializeType(typeof(UserControl));
4082 path = userControl.AppRelativeVirtualPath;
4085 typeName = WebPartUtil.SerializeType(childControl.GetType());
4087 genericWebPartID = genericWebPart.ID;
4091 typeName = WebPartUtil.SerializeType(webPart.GetType());
4095 dynamicWebPartState[4*i] = id;
4096 dynamicWebPartState[4*i + 1] = typeName;
4097 if (!String.IsNullOrEmpty(path)) {
4098 dynamicWebPartState[4*i + 2] = path;
4100 if (!String.IsNullOrEmpty(genericWebPartID)) {
4101 dynamicWebPartState[4*i + 3] = genericWebPartID;
4104 if (scope == PersonalizationScope.Shared) {
4105 state["DynamicWebPartsShared"] =
4106 new PersonalizationEntry(dynamicWebPartState, PersonalizationScope.Shared);
4109 state["DynamicWebPartsUser"] =
4110 new PersonalizationEntry(dynamicWebPartState, PersonalizationScope.User);
4114 // Save deleted connections
4117 ArrayList deletedConnections = new ArrayList();
4118 // PERF: Use the StaticConnections and DynamicConnections collections separately, instead
4119 // of using the Connections property which is created on every call.
4120 foreach (WebPartConnection connection in StaticConnections) {
4121 if (Internals.ConnectionDeleted(connection)) {
4122 deletedConnections.Add(connection);
4125 foreach (WebPartConnection connection in DynamicConnections) {
4126 if (Internals.ConnectionDeleted(connection)) {
4127 deletedConnections.Add(connection);
4131 int deletedConnectionsCount = deletedConnections.Count;
4132 if (deletedConnections.Count > 0) {
4133 string[] deletedConnectionsState = new string[deletedConnectionsCount];
4134 for (int i=0; i < deletedConnectionsCount; i++) {
4135 WebPartConnection deletedConnection = (WebPartConnection)deletedConnections[i];
4136 // Only shared connections can be deleted
4137 Debug.Assert(deletedConnection.IsShared);
4138 // In shared scope, only static connections should be deleted
4139 // In user scope, static and dynamic connections can be deleted
4140 Debug.Assert(deletedConnection.IsStatic || scope == PersonalizationScope.User);
4141 deletedConnectionsState[i] = deletedConnection.ID;
4143 if (scope == PersonalizationScope.Shared) {
4144 state["DeletedConnectionsShared"] =
4145 new PersonalizationEntry(deletedConnectionsState, PersonalizationScope.Shared);
4148 state["DeletedConnectionsUser"] =
4149 new PersonalizationEntry(deletedConnectionsState, PersonalizationScope.User);
4153 // Select only the dynamic Connections that should be saved for this mode
4154 ArrayList dynamicConnections = new ArrayList();
4155 foreach (WebPartConnection connection in DynamicConnections) {
4156 if (((scope == PersonalizationScope.User) && (!connection.IsShared)) ||
4157 ((scope == PersonalizationScope.Shared) && (connection.IsShared))) {
4158 dynamicConnections.Add(connection);
4162 int dynamicConnectionsCount = dynamicConnections.Count;
4163 if (dynamicConnectionsCount > 0) {
4164 // Use a 1-dimensional array for smallest storage space
4165 object[] dynamicConnectionState = new object[dynamicConnectionsCount * 7];
4166 for (int i = 0; i < dynamicConnectionsCount; i++) {
4167 WebPartConnection connection = (WebPartConnection)dynamicConnections[i];
4168 WebPartTransformer transformer = connection.Transformer;
4170 // We should never be saving a deleted dynamic connection. If the User has deleted a
4171 // a shared connection, the connection will be saved in the Shared data, not here.
4172 Debug.Assert(!Internals.ConnectionDeleted(connection));
4174 dynamicConnectionState[7*i] = connection.ID;
4175 dynamicConnectionState[7*i + 1] = connection.ConsumerID;
4176 dynamicConnectionState[7*i + 2] = connection.ConsumerConnectionPointID;
4177 dynamicConnectionState[7*i + 3] = connection.ProviderID;
4178 dynamicConnectionState[7*i + 4] = connection.ProviderConnectionPointID;
4179 if (transformer != null) {
4180 dynamicConnectionState[7*i + 5] = transformer.GetType();
4181 dynamicConnectionState[7*i + 6] = Internals.SaveConfigurationState(transformer);
4185 if (scope == PersonalizationScope.Shared) {
4186 state["DynamicConnectionsShared"] =
4187 new PersonalizationEntry(dynamicConnectionState, PersonalizationScope.Shared);
4190 state["DynamicConnectionsUser"] =
4191 new PersonalizationEntry(dynamicConnectionState, PersonalizationScope.User);
4196 // Can be called by a derived WebPartManager to mark itself as dirty
4197 protected void SetPersonalizationDirty() {
4198 Personalization.SetDirty();
4201 // Returns true if the WebPart should currently be rendered in the Zone. Determines
4202 // which WebParts are returned by GetWebPartsForZone.
4203 private bool ShouldRenderWebPartInZone(WebPart part, WebPartZoneBase zone) {
4204 Debug.Assert(part.Zone == zone);
4206 // Never render UnauthorizedWebParts
4207 if (part is UnauthorizedWebPart) {
4214 protected void SetSelectedWebPart(WebPart webPart) {
4215 _selectedWebPart = webPart;
4218 // PropertyInfo will be null for an IPersonalizable property, since there is no associated PropertyInfo
4219 private bool ShouldExportProperty(PropertyInfo propertyInfo, Type propertyValueType,
4220 object propertyValue, out string exportString) {
4221 string propertyValueAsString = propertyValue as string;
4222 if (propertyValueAsString != null) {
4223 exportString = propertyValueAsString;
4227 TypeConverter converter = null;
4229 if (propertyInfo != null) {
4230 // See if the property itself has a type converter associated with it
4231 TypeConverterAttribute attr =
4232 Attribute.GetCustomAttribute(propertyInfo, typeof(TypeConverterAttribute), true) as TypeConverterAttribute;
4234 // Get the type using DeserializeType(), which calls BuildManager.GetType(),
4235 // since we want this to work with a non-assembly qualified typename
4236 // in the Code directory.
4237 Type converterType = WebPartUtil.DeserializeType(attr.ConverterTypeName, false);
4238 // SECURITY: Check that the type is a subclass of TypeConverter before instantiating.
4239 if (converterType != null && converterType.IsSubclassOf(typeof(TypeConverter))) {
4240 TypeConverter tempConverter = (TypeConverter)(Internals.CreateObjectFromType(converterType));
4241 if (Util.CanConvertToFrom(tempConverter, typeof(string))) {
4242 converter = tempConverter;
4248 if (converter == null) {
4249 // If there was no valid type converter on the property info, look on the type of the value
4250 TypeConverter tempConverter = TypeDescriptor.GetConverter(propertyValueType);
4251 if (Util.CanConvertToFrom(tempConverter, typeof(string))) {
4252 converter = tempConverter;
4256 // Only export property if we found a valid type converter (VSWhidbey 496495)
4257 if (converter != null) {
4258 if (propertyValue != null) {
4259 exportString = converter.ConvertToInvariantString(propertyValue);
4263 // Special-case null value
4264 exportString = null;
4269 exportString = null;
4270 if (propertyInfo == null && propertyValue == null) {
4271 // Always want to export a null IPersonalizable value, since we will never have a type
4272 // converter for the value. However, we should not export a null Personalizable value
4273 // unless the propertyInfo had a type converter, since we may not be able to import a
4274 // null value, since the property may be a value type that cannot accept null as a value.
4275 // (VSWhidbey 537895)
4286 /// Returns true if the connection should be removed from the dynamic connection
4287 /// collection when deleted.
4289 private bool ShouldRemoveConnection(WebPartConnection connection) {
4290 Debug.Assert(Personalization.IsModifiable);
4292 if (connection.IsShared && (Personalization.Scope == PersonalizationScope.User)) {
4293 // Can't remove shared connection in user mode
4301 /// <internalonly />
4302 protected override void TrackViewState() {
4303 Personalization.ApplyPersonalizationState();
4304 base.TrackViewState();
4307 // Throw if the type cannot be loaded by BuildManager
4308 // For instance, we cannot load a type defined in the Page class
4309 private void VerifyType(Control control) {
4310 // Don't need to verify type of UserControls, since we load them using
4311 // their path instead of their type
4312 if (control is UserControl) {
4316 Type type = control.GetType();
4317 string typeName = WebPartUtil.SerializeType(type);
4318 Type loadedType = WebPartUtil.DeserializeType(typeName, /* throwOnError */ false);
4319 if (loadedType != type) {
4320 throw new InvalidOperationException(
4321 SR.GetString(SR.WebPartManager_CantAddControlType, typeName));
4325 #region Implementation of IPersonalizable
4327 bool IPersonalizable.IsDirty {
4329 return IsCustomPersonalizationStateDirty;
4334 void IPersonalizable.Load(PersonalizationDictionary state) {
4335 LoadCustomPersonalizationState(state);
4339 void IPersonalizable.Save(PersonalizationDictionary state) {
4340 SaveCustomPersonalizationState(state);
4344 private sealed class WebPartManagerControlCollection : ControlCollection {
4346 private WebPartManager _manager;
4348 public WebPartManagerControlCollection(WebPartManager owner) : base(owner) {
4350 SetCollectionReadOnly(SR.WebPartManager_CannotModify);
4353 internal void AddWebPart(WebPart webPart) {
4354 string originalError = SetCollectionReadOnly(null);
4355 // Extra try-catch block to prevent elevation of privilege attack via exception filter
4358 AddWebPartHelper(webPart);
4361 SetCollectionReadOnly(originalError);
4369 private void AddWebPartHelper(WebPart webPart) {
4370 string partID = webPart.ID;
4371 if (String.IsNullOrEmpty(partID)) {
4372 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoWebPartID));
4374 if (_manager._partAndChildControlIDs.Contains(partID)) {
4375 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DuplicateWebPartID, partID));
4378 // Add to dictionary to prevent duplicate IDs, even if this part is not authorized. Don't want page
4379 // developer to have 2 parts with the same ID, and not get the exception until they are both authorized.
4380 _manager._partAndChildControlIDs.Add(partID, null);
4382 // Check and add child control ID (VSWhidbey 339482)
4383 GenericWebPart genericWebPart = webPart as GenericWebPart;
4384 if (genericWebPart != null) {
4385 string childControlID = genericWebPart.ChildControl.ID;
4387 if (String.IsNullOrEmpty(childControlID)) {
4388 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoChildControlID));
4391 if (_manager._partAndChildControlIDs.Contains(childControlID)) {
4392 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DuplicateWebPartID, childControlID));
4395 _manager._partAndChildControlIDs.Add(childControlID, null);
4398 _manager.Internals.SetIsStandalone(webPart, false);
4399 webPart.SetWebPartManager(_manager);
4402 // Invalidate the part dictionary if it has already been created
4403 _manager._partsForZone = null;
4406 internal void AddWebPartsFromZone(WebPartZoneBase zone, WebPartCollection webParts) {
4407 if ((webParts != null) && (webParts.Count != 0)) {
4408 string originalError = SetCollectionReadOnly(null);
4410 // Extra try-catch block to prevent elevation of privilege attack via exception filter
4413 string zoneID = zone.ID;
4416 foreach (WebPart webPart in webParts) {
4417 // Need to set IsShared before calling IsAuthorized
4418 _manager.Internals.SetIsShared(webPart, true);
4420 WebPart webPartOrProxy = webPart;
4421 if (!_manager.IsAuthorized(webPart)) {
4422 webPartOrProxy = new UnauthorizedWebPart(webPart);
4425 _manager.Internals.SetIsStatic(webPartOrProxy, true);
4426 _manager.Internals.SetIsShared(webPartOrProxy, true);
4427 _manager.Internals.SetZoneID(webPartOrProxy, zoneID);
4428 _manager.Internals.SetZoneIndex(webPartOrProxy, index);
4430 AddWebPartHelper(webPartOrProxy);
4435 SetCollectionReadOnly(originalError);
4443 internal void RemoveWebPart(WebPart webPart) {
4444 string originalError = SetCollectionReadOnly(null);
4445 // Extra try-catch block to prevent elevation of privilege attack via exception filter
4448 _manager._partAndChildControlIDs.Remove(webPart.ID);
4450 // Remove child control ID (VSWhidbey 339482)
4451 GenericWebPart genericWebPart = webPart as GenericWebPart;
4452 if (genericWebPart != null) {
4453 _manager._partAndChildControlIDs.Remove(genericWebPart.ChildControl.ID);
4457 _manager._hasDataChanged = true;
4458 webPart.SetWebPartManager(null);
4459 _manager.Internals.SetIsStandalone(webPart, true);
4461 // Invalidate the part dictionary if it has already been created
4462 _manager._partsForZone = null;
4465 SetCollectionReadOnly(originalError);
4474 private sealed class BrowseWebPartDisplayMode : WebPartDisplayMode {
4476 public BrowseWebPartDisplayMode() : base("Browse") {
4480 private sealed class CatalogWebPartDisplayMode : WebPartDisplayMode {
4482 public CatalogWebPartDisplayMode() : base("Catalog") {
4485 public override bool AllowPageDesign {
4491 public override bool AssociatedWithToolZone {
4497 public override bool RequiresPersonalization {
4503 public override bool ShowHiddenWebParts {
4510 private sealed class ConnectionPointKey {
4511 // DevDiv Bugs 38677
4512 // used as the Cache key for Connection Points, using Type and Culture
4514 private CultureInfo _culture;
4515 private CultureInfo _uiCulture;
4517 public ConnectionPointKey(Type type, CultureInfo culture, CultureInfo uiCulture) {
4518 Debug.Assert(type != null && culture != null && uiCulture != null);
4522 _uiCulture = uiCulture;
4525 public override bool Equals(object obj) {
4530 ConnectionPointKey other = obj as ConnectionPointKey;
4531 return (other != null) &&
4532 (other._type.Equals(_type)) &&
4533 (other._culture.Equals(_culture)) &&
4534 (other._uiCulture.Equals(_uiCulture));
4537 [SuppressMessage("Microsoft.Usage", "CA2303:FlagTypeGetHashCode", Justification = "The types are Sytem.Web.UI.Control derived classes and not com interop types.")]
4538 public override int GetHashCode()
4540 int typeHashCode = _type.GetHashCode();
4541 // This is the algorithm used in Whidbey to combine hashcodes.
4542 // It adheres better than a simple XOR to the randomness requirement for hashcodes.
4543 int hashCode = ((typeHashCode << 5) + typeHashCode) ^ _culture.GetHashCode();
4544 return ((hashCode << 5) + hashCode) ^ _uiCulture.GetHashCode();
4548 private sealed class ConnectWebPartDisplayMode : WebPartDisplayMode {
4550 public ConnectWebPartDisplayMode() : base("Connect") {
4553 public override bool AllowPageDesign {
4559 public override bool AssociatedWithToolZone {
4565 public override bool RequiresPersonalization {
4571 public override bool ShowHiddenWebParts {
4578 private sealed class DesignWebPartDisplayMode : WebPartDisplayMode {
4580 public DesignWebPartDisplayMode() : base("Design") {
4583 public override bool AllowPageDesign {
4589 public override bool RequiresPersonalization {
4595 public override bool ShowHiddenWebParts {
4602 private sealed class EditWebPartDisplayMode : WebPartDisplayMode {
4604 public EditWebPartDisplayMode() : base("Edit") {
4607 public override bool AllowPageDesign {
4613 public override bool AssociatedWithToolZone {
4619 public override bool RequiresPersonalization {
4625 public override bool ShowHiddenWebParts {