1 //------------------------------------------------------------------------------
2 // <copyright file="WebPartManager.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //------------------------------------------------------------------------------
6 
7 namespace System.Web.UI.WebControls.WebParts {
8 
9     using System;
10     using System.Collections;
11     using System.Collections.Specialized;
12     using System.ComponentModel;
13     using System.Diagnostics.CodeAnalysis;
14     using System.Drawing;
15     using System.Globalization;
16     using System.IO;
17     using System.Reflection;
18     using System.Security;
19     using System.Security.Permissions;
20     using System.Text;
21     using System.Web;
22     using System.Web.Configuration;
23     using System.Web.UI;
24     using System.Web.UI.WebControls;
25     using System.Web.Util;
26     using System.Xml;
27 
28     [
29     Bindable(false),
30     Designer("System.Web.UI.Design.WebControls.WebParts.WebPartManagerDesigner, " + AssemblyRef.SystemDesign),
31     NonVisualControl(),
32     ParseChildren(true),
33     PersistChildren(false),
34     ViewStateModeById(),
35     ]
36     public class WebPartManager : Control, INamingContainer, IPersonalizable {
37 
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();
43 
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;
48 
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();
68 
69         private PermissionSet _minimalPermissionSet;
70         private PermissionSet _mediumPermissionSet;
71         private bool? _usePermitOnly;
72 
73         private const string DynamicConnectionIDPrefix = "c";
74         private const string DynamicWebPartIDPrefix = "wp";
75 
76         private const int baseIndex = 0;
77         private const int selectedWebPartIndex = 1;
78         private const int displayModeIndex = 2;
79         private const int controlStateArrayLength = 3;
80 
81         private WebPartPersonalization _personalization;
82         private WebPartDisplayMode _displayMode;
83         private WebPartDisplayModeCollection _displayModes;
84         private WebPartDisplayModeCollection _supportedDisplayModes;
85         private WebPartManagerInternals _internals;
86 
87         private bool _allowCreateDisplayTitles;
88         private bool _pageInitComplete;
89 
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;
93 
94         private PersonalizationDictionary _personalizationState;
95         private bool _hasDataChanged;
96 
97         private WebPartConnectionCollection _staticConnections;
98         private WebPartConnectionCollection _dynamicConnections;
99 
100         private WebPartZoneCollection _webPartZones;
101         private TransformerTypeCollection _availableTransformers;
102 
103         // Dictionary mapping a WebPart to its DisplayTitle.  Created and filled on demand when
104         // GetDisplayTitle() is called after PreRender.
105         private IDictionary _displayTitles;
106 
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
117 
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]" };
126 
127         // Dictionary mapping a zone to the parts in the zone.  Used by GetAllWebPartsForZone
128         // to improve performance.
129         private IDictionary _partsForZone;
130 
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;
136 
137         // Contains the IDs of Zones already added.  An exception is thrown if a Zone is added with
138         // a duplicate ID.
139         private IDictionary _zoneIDs;
140 
141         private WebPart _selectedWebPart;
142 
143         private bool _renderClientScript;
144 
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"">
152 
153 __wpm = new WebPartManager();
154 __wpm.overlayContainerElement = {0};
155 __wpm.personalizationScopeShared = {1};
156 
157 var zoneElement;
158 var zoneObject;
159 {2}
160 </script>
161 ";
162         private const string ZoneScript = @"
163 zoneElement = document.getElementById('{0}');
164 if (zoneElement != null) {{
165     zoneObject = __wpm.AddZone(zoneElement, '{1}', {2}, {3}, '{4}');";
166 
167         private const string ZonePartScript = @"
168     zoneObject.AddWebPart(document.getElementById('{0}'), {1}, {2});";
169 
170         private const string ZoneEndScript = @"
171 }";
172 
173         private const string AuthorizationFilterName = "AuthorizationFilter";
174         private const string ImportErrorMessageName = "ImportErrorMessage";
175         private const string ZoneIDName = "ZoneID";
176         private const string ZoneIndexName = "ZoneIndex";
177 
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";
196 
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";
212 
213         /// <devdoc>
214         /// </devdoc>
WebPartManager()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 */);
221         }
222 
223         [
224         Browsable(false),
225         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
226         ]
227         public TransformerTypeCollection AvailableTransformers {
228             get {
229                 if (_availableTransformers == null) {
230                     _availableTransformers = CreateAvailableTransformers();
231                 }
232                 return _availableTransformers;
233             }
234         }
235 
236         [
237         WebCategory("Behavior"),
238         WebSysDefaultValue(SR.WebPartManager_DefaultCloseProviderWarning),
239         WebSysDescription(SR.WebPartManager_CloseProviderWarning)
240         ]
241         public virtual string CloseProviderWarning {
242             get {
243                 object o = ViewState["CloseProviderWarning"];
244                 return (o != null) ? (string)o : SR.GetString(SR.WebPartManager_DefaultCloseProviderWarning);
245             }
246             set {
247                 ViewState["CloseProviderWarning"] = value;
248             }
249         }
250 
251         [
252         Browsable(false),
253         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
254         ]
255         public WebPartConnectionCollection Connections {
256             get {
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);
262                         }
263                     }
264                 }
265                 if (_dynamicConnections != null) {
266                     foreach (WebPartConnection connection in _dynamicConnections) {
267                         if (!Internals.ConnectionDeleted(connection)) {
268                             connections.Add(connection);
269                         }
270                     }
271                 }
272                 connections.SetReadOnly(SR.WebPartManager_ConnectionsReadOnly);
273                 return connections;
274             }
275         }
276 
277         // Hide the Controls property from IntelliSense.  The developer should use the
278         // WebParts property instead.
279         [
280         EditorBrowsable(EditorBrowsableState.Never),
281         ]
282         public override ControlCollection Controls {
283             get {
284                 return base.Controls;
285             }
286         }
287 
288         [
289         WebCategory("Behavior"),
290         WebSysDefaultValue(SR.WebPartManager_DefaultDeleteWarning),
291         WebSysDescription(SR.WebPartManager_DeleteWarning)
292         ]
293         public virtual string DeleteWarning {
294             get {
295                 object o = ViewState["DeleteWarning"];
296                 return (o != null) ? (string)o : SR.GetString(SR.WebPartManager_DefaultDeleteWarning);
297             }
298             set {
299                 ViewState["DeleteWarning"] = value;
300             }
301         }
302 
303         [
304         Browsable(false),
305         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
306         ]
307         public virtual WebPartDisplayMode DisplayMode {
308             get {
309                 return _displayMode;
310             }
311             set {
312                 if (value == null) {
313                     throw new ArgumentNullException("value");
314                 }
315 
316                 if (DisplayMode == value) {
317                     return;
318                 }
319 
320                 if (SupportedDisplayModes.Contains(value) == false) {
321                     throw new ArgumentException(SR.GetString(SR.WebPartManager_InvalidDisplayMode), "value");
322                 }
323 
324                 if (!value.IsEnabled(this)) {
325                     throw new ArgumentException(SR.GetString(SR.WebPartManager_DisabledDisplayMode), "value");
326                 }
327 
328                 WebPartDisplayModeCancelEventArgs dmce = new WebPartDisplayModeCancelEventArgs(value);
329                 OnDisplayModeChanging(dmce);
330 
331                 if (_allowEventCancellation && dmce.Cancel) {
332                     return;
333                 }
334 
335                 // Custom display modes can take actions like this in the OnDisplayModeChanging method.
336                 // For example:
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
342                 //     }
343                 // }
344 
345                 // End web part connecting if necessary
346                 if ((DisplayMode == ConnectDisplayMode) && (SelectedWebPart != null)) {
347                     EndWebPartConnecting();
348                     if (SelectedWebPart != null) {
349                         // WebPartConnectModeChanging event was cancelled
350                         return;
351                     }
352                 }
353 
354                 // End web part editing if necessary
355                 if ((DisplayMode == EditDisplayMode) && (SelectedWebPart != null)) {
356                     EndWebPartEditing();
357                     if (SelectedWebPart != null) {
358                         // WebPartEditModeChanging event was cancelled
359                         return;
360                     }
361                 }
362 
363                 WebPartDisplayModeEventArgs dme = new WebPartDisplayModeEventArgs(DisplayMode);
364                 _displayMode = value;
365                 OnDisplayModeChanged(dme);
366             }
367         }
368 
369         [
370         Browsable(false),
371         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
372         ]
373         public WebPartDisplayModeCollection DisplayModes {
374             get {
375                 if (_displayModes == null) {
376                     _displayModes = CreateDisplayModes();
377                     _displayModes.SetReadOnly(SR.WebPartManager_DisplayModesReadOnly);
378                 }
379 
380                 return _displayModes;
381             }
382         }
383 
384         protected internal WebPartConnectionCollection DynamicConnections {
385             get {
386                 if (_dynamicConnections == null) {
387                     _dynamicConnections = new WebPartConnectionCollection(this);
388                 }
389                 return _dynamicConnections;
390             }
391         }
392 
393         [
394         DefaultValue(true),
395         WebCategory("Behavior"),
396         WebSysDescription(SR.WebPartManager_EnableClientScript)
397         ]
398         public virtual bool EnableClientScript {
399             get {
400                 object o = ViewState["EnableClientScript"];
401                 return (o != null) ? (bool)o : true;
402             }
403             set {
404                 ViewState["EnableClientScript"] = value;
405             }
406         }
407 
408         // Theming must be enabled, so the WebPart child controls have theming enabled
409         [
410         Browsable(false),
411         DefaultValue(true),
412         EditorBrowsable(EditorBrowsableState.Never),
413         ]
414         public override bool EnableTheming {
415             get {
416                 return true;
417             }
418             set {
419                 throw new NotSupportedException(SR.GetString(SR.WebPartManager_CantSetEnableTheming));
420             }
421         }
422 
423         [
424         WebCategory("Behavior"),
425         WebSysDefaultValue(SR.WebPartChrome_ConfirmExportSensitive),
426         WebSysDescription(SR.WebPartManager_ExportSensitiveDataWarning)
427         ]
428         public virtual string ExportSensitiveDataWarning {
429             get {
430                 object o = ViewState["ExportSensitiveDataWarning"];
431                 return (o != null) ? (string)o : SR.GetString(SR.WebPartChrome_ConfirmExportSensitive);
432             }
433             set {
434                 ViewState["ExportSensitiveDataWarning"] = value;
435             }
436         }
437 
438         [
439         EditorBrowsable(EditorBrowsableState.Never),
440         ]
441         protected WebPartManagerInternals Internals {
442             get {
443                 if (_internals == null) {
444                     _internals = new WebPartManagerInternals(this);
445                 }
446                 return _internals;
447             }
448         }
449 
450         /// <devdoc>
451         /// </devdoc>
452         protected virtual bool IsCustomPersonalizationStateDirty {
453             get {
454                 return _hasDataChanged;
455             }
456         }
457 
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 {
462             get {
463                 if (_mediumPermissionSet == null) {
464                     _mediumPermissionSet = new PermissionSet(PermissionState.None);
465                     _mediumPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
466                     _mediumPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Medium));
467                 }
468                 return _mediumPermissionSet;
469             }
470         }
471 
472         // PermissionSet that allows only Execution and AspNetHostingPermissionLevel.Minimal.
473         // Used for during Import for everything except type deserialization.
474         protected virtual PermissionSet MinimalPermissionSet {
475             get {
476                 if (_minimalPermissionSet == null) {
477                     _minimalPermissionSet = new PermissionSet(PermissionState.None);
478                     _minimalPermissionSet.AddPermission(new SecurityPermission(SecurityPermissionFlag.Execution));
479                     _minimalPermissionSet.AddPermission(new AspNetHostingPermission(AspNetHostingPermissionLevel.Minimal));
480                 }
481                 return _minimalPermissionSet;
482             }
483         }
484 
485         /// <devdoc>
486         /// </devdoc>
487         [
488         DefaultValue(null),
489         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
490         NotifyParentProperty(true),
491         PersistenceMode(PersistenceMode.InnerProperty),
492         WebCategory("Behavior"),
493         WebSysDescription(SR.WebPartManager_Personalization)
494         ]
495         public WebPartPersonalization Personalization {
496             get {
497                 if (_personalization == null) {
498                     _personalization = CreatePersonalization();
499                 }
500 
501                 return _personalization;
502             }
503         }
504 
505         internal bool RenderClientScript {
506             get {
507                 return _renderClientScript;
508             }
509         }
510 
511         [
512         Browsable(false),
513         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
514         ]
515         public WebPart SelectedWebPart {
516             get {
517                 return _selectedWebPart;
518             }
519         }
520 
521         [
522         Browsable(false),
523         DefaultValue(""),
524         EditorBrowsable(EditorBrowsableState.Never),
525         ]
526         public override string SkinID {
527             get {
528                 return String.Empty;
529             }
530             set {
531                 throw new NotSupportedException(SR.GetString(SR.NoThemingSupport, this.GetType().Name));
532             }
533         }
534 
535         [
536         DefaultValue(null),
537         DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
538         MergableProperty(false),
539         PersistenceMode(PersistenceMode.InnerProperty),
540         WebCategory("Behavior"),
541         WebSysDescription(SR.WebPartManager_StaticConnections),
542         ]
543         public WebPartConnectionCollection StaticConnections {
544             get {
545                 if (_staticConnections == null) {
546                     _staticConnections = new WebPartConnectionCollection(this);
547                 }
548                 return _staticConnections;
549             }
550         }
551 
552         [
553         Browsable(false),
554         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
555         ]
556         public WebPartDisplayModeCollection SupportedDisplayModes {
557             get {
558                 if (_supportedDisplayModes == null) {
559                     _supportedDisplayModes = new WebPartDisplayModeCollection();
560 
561                     foreach (WebPartDisplayMode mode in DisplayModes) {
562                         if (mode.AssociatedWithToolZone == false) {
563                             _supportedDisplayModes.Add(mode);
564                         }
565                     }
566 
567                     _supportedDisplayModes.SetReadOnly(SR.WebPartManager_DisplayModesReadOnly);
568                 }
569                 return _supportedDisplayModes;
570             }
571         }
572 
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 {
576             get {
577                 if (!_usePermitOnly.HasValue) {
578                     _usePermitOnly =  RuntimeConfig.GetAppConfig().Trust.LegacyCasModel;
579                 }
580                 return _usePermitOnly.Value;
581             }
582         }
583 
584         [
585         Bindable(false),
586         Browsable(false),
587         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
588         EditorBrowsable(EditorBrowsableState.Never),
589         ]
590         public override bool Visible {
591             get {
592                 // Even though we are a non-visual control, this returns true, because we want our
593                 // child controls (the WebParts) to be Visible.
594                 return true;
595             }
596             set {
597                 throw new NotSupportedException(SR.GetString(SR.ControlNonVisual, this.GetType().Name));
598             }
599         }
600 
601         /// <devdoc>
602         /// All the WebParts on the page.
603         /// </devdoc>
604         [
605         Browsable(false),
606         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
607         ]
608         public WebPartCollection WebParts {
609             get {
610                 // PERF: Consider changing WebPartCollection so it just wraps the ControlCollection,
611                 // instead of copying the controls to a new collection.
612                 if (HasControls()) {
613                     return new WebPartCollection(Controls);
614                 }
615                 else {
616                     return new WebPartCollection();
617                 }
618             }
619         }
620 
621         [
622         Browsable(false),
623         DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
624         ]
625         public WebPartZoneCollection Zones {
626             get {
627                 return _webPartZones;
628             }
629         }
630 
631         [
632         WebCategory("Action"),
633         WebSysDescription(SR.WebPartManager_AuthorizeWebPart)
634         ]
635         public event WebPartAuthorizationEventHandler AuthorizeWebPart {
636             add {
637                 Events.AddHandler(AuthorizeWebPartEvent, value);
638             }
639             remove {
640                 Events.RemoveHandler(AuthorizeWebPartEvent, value);
641             }
642         }
643 
644         [
645         WebCategory("Action"),
646         WebSysDescription(SR.WebPartManager_ConnectionsActivated)
647         ]
648         public event EventHandler ConnectionsActivated {
649             add {
650                 Events.AddHandler(ConnectionsActivatedEvent, value);
651             }
652             remove {
653                 Events.RemoveHandler(ConnectionsActivatedEvent, value);
654             }
655         }
656 
657         [
658         WebCategory("Action"),
659         WebSysDescription(SR.WebPartManager_ConnectionsActivating)
660         ]
661         public event EventHandler ConnectionsActivating {
662             add {
663                 Events.AddHandler(ConnectionsActivatingEvent, value);
664             }
665             remove {
666                 Events.RemoveHandler(ConnectionsActivatingEvent, value);
667             }
668         }
669 
670         [
671         WebCategory("Action"),
672         WebSysDescription(SR.WebPartManager_DisplayModeChanged)
673         ]
674         public event WebPartDisplayModeEventHandler DisplayModeChanged {
675             add {
676                 Events.AddHandler(DisplayModeChangedEvent, value);
677             }
678             remove {
679                 Events.RemoveHandler(DisplayModeChangedEvent, value);
680             }
681         }
682 
683         [
684         WebCategory("Action"),
685         WebSysDescription(SR.WebPartManager_DisplayModeChanging)
686         ]
687         public event WebPartDisplayModeCancelEventHandler DisplayModeChanging {
688             add {
689                 Events.AddHandler(DisplayModeChangingEvent, value);
690             }
691             remove {
692                 Events.RemoveHandler(DisplayModeChangingEvent, value);
693             }
694         }
695 
696         [
697         WebCategory("Action"),
698         WebSysDescription(SR.WebPartManager_SelectedWebPartChanged)
699         ]
700         public event WebPartEventHandler SelectedWebPartChanged {
701             add {
702                 Events.AddHandler(SelectedWebPartChangedEvent, value);
703             }
704             remove {
705                 Events.RemoveHandler(SelectedWebPartChangedEvent, value);
706             }
707         }
708 
709         [
710         WebCategory("Action"),
711         WebSysDescription(SR.WebPartManager_SelectedWebPartChanging)
712         ]
713         public event WebPartCancelEventHandler SelectedWebPartChanging {
714             add {
715                 Events.AddHandler(SelectedWebPartChangingEvent, value);
716             }
717             remove {
718                 Events.RemoveHandler(SelectedWebPartChangingEvent, value);
719             }
720         }
721 
722         [
723         WebCategory("Action"),
724         WebSysDescription(SR.WebPartManager_WebPartAdded)
725         ]
726         public event WebPartEventHandler WebPartAdded {
727             add {
728                 Events.AddHandler(WebPartAddedEvent, value);
729             }
730             remove {
731                 Events.RemoveHandler(WebPartAddedEvent, value);
732             }
733         }
734 
735         [
736         WebCategory("Action"),
737         WebSysDescription(SR.WebPartManager_WebPartAdding)
738         ]
739         public event WebPartAddingEventHandler WebPartAdding {
740             add {
741                 Events.AddHandler(WebPartAddingEvent, value);
742             }
743             remove {
744                 Events.RemoveHandler(WebPartAddingEvent, value);
745             }
746         }
747 
748         [
749         WebCategory("Action"),
750         WebSysDescription(SR.WebPartManager_WebPartClosed)
751         ]
752         public event WebPartEventHandler WebPartClosed {
753             add {
754                 Events.AddHandler(WebPartClosedEvent, value);
755             }
756             remove {
757                 Events.RemoveHandler(WebPartClosedEvent, value);
758             }
759         }
760 
761         [
762         WebCategory("Action"),
763         WebSysDescription(SR.WebPartManager_WebPartClosing)
764         ]
765         public event WebPartCancelEventHandler WebPartClosing {
766             add {
767                 Events.AddHandler(WebPartClosingEvent, value);
768             }
769             remove {
770                 Events.RemoveHandler(WebPartClosingEvent, value);
771             }
772         }
773 
774         [
775         WebCategory("Action"),
776         WebSysDescription(SR.WebPartManager_WebPartDeleted)
777         ]
778         public event WebPartEventHandler WebPartDeleted {
779             add {
780                 Events.AddHandler(WebPartDeletedEvent, value);
781             }
782             remove {
783                 Events.RemoveHandler(WebPartDeletedEvent, value);
784             }
785         }
786 
787         [
788         WebCategory("Action"),
789         WebSysDescription(SR.WebPartManager_WebPartDeleting)
790         ]
791         public event WebPartCancelEventHandler WebPartDeleting {
792             add {
793                 Events.AddHandler(WebPartDeletingEvent, value);
794             }
795             remove {
796                 Events.RemoveHandler(WebPartDeletingEvent, value);
797             }
798         }
799 
800         [
801         WebCategory("Action"),
802         WebSysDescription(SR.WebPartManager_WebPartMoved)
803         ]
804         public event WebPartEventHandler WebPartMoved {
805             add {
806                 Events.AddHandler(WebPartMovedEvent, value);
807             }
808             remove {
809                 Events.RemoveHandler(WebPartMovedEvent, value);
810             }
811         }
812 
813         [
814         WebCategory("Action"),
815         WebSysDescription(SR.WebPartManager_WebPartMoving)
816         ]
817         public event WebPartMovingEventHandler WebPartMoving {
818             add {
819                 Events.AddHandler(WebPartMovingEvent, value);
820             }
821             remove {
822                 Events.RemoveHandler(WebPartMovingEvent, value);
823             }
824         }
825 
826         [
827         WebCategory("Action"),
828         WebSysDescription(SR.WebPartManager_WebPartsConnected)
829         ]
830         public event WebPartConnectionsEventHandler WebPartsConnected {
831             add {
832                 Events.AddHandler(WebPartsConnectedEvent, value);
833             }
834             remove {
835                 Events.RemoveHandler(WebPartsConnectedEvent, value);
836             }
837         }
838 
839         [
840         WebCategory("Action"),
841         WebSysDescription(SR.WebPartManager_WebPartsConnecting)
842         ]
843         public event WebPartConnectionsCancelEventHandler WebPartsConnecting {
844             add {
845                 Events.AddHandler(WebPartsConnectingEvent, value);
846             }
847             remove {
848                 Events.RemoveHandler(WebPartsConnectingEvent, value);
849             }
850         }
851 
852         [
853         WebCategory("Action"),
854         WebSysDescription(SR.WebPartManager_WebPartsDisconnected)
855         ]
856         public event WebPartConnectionsEventHandler WebPartsDisconnected {
857             add {
858                 Events.AddHandler(WebPartsDisconnectedEvent, value);
859             }
860             remove {
861                 Events.RemoveHandler(WebPartsDisconnectedEvent, value);
862             }
863         }
864 
865         [
866         WebCategory("Action"),
867         WebSysDescription(SR.WebPartManager_WebPartsDisconnecting)
868         ]
869         public event WebPartConnectionsCancelEventHandler WebPartsDisconnecting {
870             add {
871                 Events.AddHandler(WebPartsDisconnectingEvent, value);
872             }
873             remove {
874                 Events.RemoveHandler(WebPartsDisconnectingEvent, value);
875             }
876         }
877 
ActivateConnections()878         protected virtual void ActivateConnections() {
879             try {
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();
885                 }
886             }
887             finally {
888                 _allowEventCancellation = true;
889             }
890         }
891 
892         // Called by WebPartManagerInternals
AddWebPart(WebPart webPart)893         internal void AddWebPart(WebPart webPart) {
894             ((WebPartManagerControlCollection)Controls).AddWebPart(webPart);
895         }
896 
AddDynamicWebPartToZone(WebPart webPart, WebPartZoneBase zone, int zoneIndex)897         private WebPart AddDynamicWebPartToZone(WebPart webPart, WebPartZoneBase zone, int zoneIndex) {
898             Debug.Assert(Personalization.IsModifiable);
899 
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);
902 
903             // Only add WebPart if IsAuthorized(webPart) == true
904             if (!IsAuthorized(webPart)) {
905                 return null;
906             }
907 
908             WebPart newWebPart = CopyWebPart(webPart);
909             Internals.SetIsStatic(newWebPart, false);
910             Internals.SetIsShared(newWebPart, Personalization.Scope == PersonalizationScope.Shared);
911 
912             AddWebPartToZone(newWebPart, zone, zoneIndex);
913             Internals.AddWebPart(newWebPart);
914 
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);
919 
920             // Raise event at very end of Add method
921             OnWebPartAdded(new WebPartEventArgs(newWebPart));
922 
923             return newWebPart;
924         }
925 
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.
AddWebPart(WebPart webPart, WebPartZoneBase zone, int zoneIndex)928         public WebPart AddWebPart(WebPart webPart, WebPartZoneBase zone, int zoneIndex) {
929             Personalization.EnsureEnabled(/* ensureModifiable */ true);
930 
931             if (webPart == null) {
932                 throw new ArgumentNullException("webPart");
933             }
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.
936             if (zone == null) {
937                 throw new ArgumentNullException("zone");
938             }
939             if (_webPartZones.Contains(zone) == false) {
940                 throw new ArgumentException(SR.GetString(SR.WebPartManager_MustRegister), "zone");
941             }
942             if (zoneIndex < 0) {
943                 throw new ArgumentOutOfRangeException("zoneIndex");
944             }
945             if (webPart.Zone != null && !webPart.IsClosed) {
946                 throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyInZone), "webPart");
947             }
948 
949             WebPartAddingEventArgs e = new WebPartAddingEventArgs(webPart, zone, zoneIndex);
950             OnWebPartAdding(e);
951             if (_allowEventCancellation && e.Cancel) {
952                 return null;
953             }
954 
955             WebPart addedWebPart;
956 
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));
963             } else {
964                 addedWebPart = AddDynamicWebPartToZone(webPart, zone, zoneIndex);
965                 // OnWebPartAdded() is called by AddDynamicWebPartToZone
966             }
967 
968 #if DEBUG
969             CheckPartZoneIndexes(zone);
970 #endif
971 
972             return addedWebPart;
973         }
974 
975         /// <devdoc>
976         /// Adds the part to the dictionary mapping zones to parts.
977         /// </devdoc>
AddWebPartToDictionary(WebPart webPart)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;
986                     }
987                     partsForZone.Add(webPart, null);
988                 }
989             }
990         }
991 
992         /// <devdoc>
993         /// Adds a web part to a zone at the specified zoneIndex, and renumbers all the parts in the zone
994         /// sequentially.
995         /// </devdoc>
AddWebPartToZone(WebPart webPart, WebPartZoneBase zone, int zoneIndex)996         private void AddWebPartToZone(WebPart webPart, WebPartZoneBase zone, int zoneIndex) {
997             Debug.Assert(webPart.Zone == null || webPart.IsClosed);
998 
999             // All the parts for the zone
1000             IList allParts = GetAllWebPartsForZone(zone);
1001 
1002             // The parts for the zone that were actually rendered
1003             WebPartCollection renderedParts = GetWebPartsForZone(zone);
1004 
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);
1012             }
1013             else {
1014                 allPartsDestinationIndex = allParts.Count;
1015             }
1016 
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);
1021             }
1022             for (int i = allPartsDestinationIndex; i < allParts.Count; i++) {
1023                 WebPart part = ((WebPart)allParts[i]);
1024                 Internals.SetZoneIndex(part, i + 1);
1025             }
1026 
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);
1031 
1032             _hasDataChanged = true;
1033 
1034             AddWebPartToDictionary(webPart);
1035         }
1036 
BeginWebPartConnecting(WebPart webPart)1037         public virtual void BeginWebPartConnecting(WebPart webPart) {
1038             Personalization.EnsureEnabled(/* ensureModifiable */ true);
1039 
1040             if (webPart == null) {
1041                 throw new ArgumentNullException("webPart");
1042             }
1043 
1044             if (webPart.IsClosed) {
1045                 throw new ArgumentException(SR.GetString(SR.WebPartManager_CantBeginConnectingClosed), "webPart");
1046             }
1047 
1048             if (!Controls.Contains(webPart)) {
1049                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
1050             }
1051 
1052             if (DisplayMode != ConnectDisplayMode) {
1053                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_MustBeInConnect));
1054             }
1055 
1056             if (webPart == SelectedWebPart) {
1057                 throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyInConnect), "webPart");
1058             }
1059 
1060             WebPartCancelEventArgs ce = new WebPartCancelEventArgs(webPart);
1061             OnSelectedWebPartChanging(ce);
1062             if (_allowEventCancellation && ce.Cancel) {
1063                 return;
1064             }
1065 
1066             if (SelectedWebPart != null) {
1067                 EndWebPartConnecting();
1068                 if (SelectedWebPart != null) {
1069                     // The ConnectModeChange was cancelled
1070                     return;
1071                 }
1072             }
1073 
1074             SetSelectedWebPart(webPart);
1075 
1076             Internals.CallOnConnectModeChanged(webPart);
1077 
1078             OnSelectedWebPartChanged(new WebPartEventArgs(webPart));
1079         }
1080 
BeginWebPartEditing(WebPart webPart)1081         public virtual void BeginWebPartEditing(WebPart webPart) {
1082             Personalization.EnsureEnabled(/* ensureModifiable */ true);
1083 
1084             if (webPart == null) {
1085                 throw new ArgumentNullException("webPart");
1086             }
1087 
1088             if (webPart.IsClosed) {
1089                 throw new ArgumentException(SR.GetString(SR.WebPartManager_CantBeginEditingClosed), "webPart");
1090             }
1091 
1092             if (!Controls.Contains(webPart)) {
1093                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
1094             }
1095 
1096             if (DisplayMode != EditDisplayMode) {
1097                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_MustBeInEdit));
1098             }
1099 
1100             if (webPart == SelectedWebPart) {
1101                 throw new ArgumentException(SR.GetString(SR.WebPartManager_AlreadyInEdit), "webPart");
1102             }
1103 
1104             WebPartCancelEventArgs ce = new WebPartCancelEventArgs(webPart);
1105             OnSelectedWebPartChanging(ce);
1106             if (_allowEventCancellation && ce.Cancel) {
1107                 return;
1108             }
1109 
1110             if (SelectedWebPart != null) {
1111                 EndWebPartEditing();
1112                 if (SelectedWebPart != null) {
1113                     // The EditModeChange was cancelled
1114                     return;
1115                 }
1116             }
1117 
1118             SetSelectedWebPart(webPart);
1119 
1120             Internals.CallOnEditModeChanged(webPart);
1121 
1122             OnSelectedWebPartChanged(new WebPartEventArgs(webPart));
1123         }
1124 
1125 #if DEBUG
1126         /// <devdoc>
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.
1129         /// </devdoc>
CheckPartZoneIndexes(WebPartZoneBase zone)1130         private void CheckPartZoneIndexes(WebPartZoneBase zone) {
1131             ICollection parts = GetAllWebPartsForZone(zone);
1132             int index = 0;
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);
1140                     }
1141                     Debug.Assert(false, builder.ToString());
1142                     return;
1143                 }
1144                 index++;
1145             }
1146         }
1147 #endif // DEBUG
1148 
CheckRenderClientScript()1149         protected virtual bool CheckRenderClientScript() {
1150             bool renderClientScript = false;
1151 
1152             if (EnableClientScript && Page != null) {
1153                 HttpBrowserCapabilities browserCaps = Page.Request.Browser;
1154 
1155                 // Win32 IE5.5+ and JScript 5.5+
1156                 if (browserCaps.Win32 && (browserCaps.MSDomVersion.CompareTo(new Version(5, 5)) >= 0)) {
1157                     renderClientScript = true;
1158                 }
1159             }
1160 
1161             return renderClientScript;
1162         }
1163 
1164         // When a Zone is deleted, any web parts in that zone should move to the page catalog.
1165         // VSWhidbey 77708
CloseOrphanedParts()1166         private void CloseOrphanedParts() {
1167             // PERF: Use Controls instead of WebParts property, to avoid creating another collection
1168             if (HasControls()) {
1169                 try {
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) {
1175                             CloseWebPart(part);
1176                         }
1177                     }
1178                 }
1179                 finally {
1180                     _allowEventCancellation = true;
1181                 }
1182             }
1183         }
1184 
CanConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint, WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint)1185         public bool CanConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1186                                        WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint) {
1187             return CanConnectWebParts(provider, providerConnectionPoint, consumer, consumerConnectionPoint, null);
1188         }
1189 
CanConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint, WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint, WebPartTransformer transformer)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);
1195         }
1196 
CanConnectWebPartsCore(WebPart provider, ProviderConnectionPoint providerConnectionPoint, WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint, WebPartTransformer transformer, bool throwOnError)1197         private bool CanConnectWebPartsCore(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1198                                             WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint,
1199                                             WebPartTransformer transformer, bool throwOnError) {
1200             if (!Personalization.IsModifiable) {
1201                 if (throwOnError) {
1202                     // Will throw appropriate exception
1203                     Personalization.EnsureEnabled(/* ensureModifiable */ true);
1204                 }
1205                 else {
1206                     return false;
1207                 }
1208             }
1209 
1210             if (provider == null) {
1211                 throw new ArgumentNullException("provider");
1212             }
1213             if (!Controls.Contains(provider)) {
1214                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "provider");
1215             }
1216 
1217             if (consumer == null) {
1218                 throw new ArgumentNullException("consumer");
1219             }
1220             if (!Controls.Contains(consumer)) {
1221                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "consumer");
1222             }
1223 
1224             if (providerConnectionPoint == null) {
1225                 throw new ArgumentNullException("providerConnectionPoint");
1226             }
1227             if (consumerConnectionPoint == null) {
1228                 throw new ArgumentNullException("consumerConnectionPoint");
1229             }
1230 
1231             Control providerControl = provider.ToControl();
1232             Control consumerControl = consumer.ToControl();
1233 
1234             if (providerConnectionPoint.ControlType != providerControl.GetType()) {
1235                 throw new ArgumentException(SR.GetString(SR.WebPartManager_InvalidConnectionPoint), "providerConnectionPoint");
1236             }
1237             if (consumerConnectionPoint.ControlType != consumerControl.GetType()) {
1238                 throw new ArgumentException(SR.GetString(SR.WebPartManager_InvalidConnectionPoint), "consumerConnectionPoint");
1239             }
1240 
1241             if (provider == consumer) {
1242                 if (throwOnError) {
1243                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectToSelf));
1244                 }
1245                 else {
1246                     return false;
1247                 }
1248             }
1249 
1250             if (provider.IsClosed) {
1251                 if (throwOnError) {
1252                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectClosed, provider.ID));
1253                 }
1254                 else {
1255                     return false;
1256                 }
1257             }
1258 
1259             if (consumer.IsClosed) {
1260                 if (throwOnError) {
1261                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectClosed, consumer.ID));
1262                 }
1263                 else {
1264                     return false;
1265                 }
1266             }
1267 
1268             if (!providerConnectionPoint.GetEnabled(providerControl)) {
1269                 if (throwOnError) {
1270                     throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_DisabledConnectionPoint, providerConnectionPoint.ID, provider.ID));
1271                 }
1272                 else {
1273                     return false;
1274                 }
1275             }
1276 
1277             if (!consumerConnectionPoint.GetEnabled(consumerControl)) {
1278                 if (throwOnError) {
1279                     throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_DisabledConnectionPoint, consumerConnectionPoint.ID, consumer.ID));
1280                 }
1281                 else {
1282                     return false;
1283                 }
1284             }
1285 
1286             // Check AllowsMultipleConnections on each ConnectionPoint
1287             if (!providerConnectionPoint.AllowsMultipleConnections) {
1288                 foreach (WebPartConnection c in Connections) {
1289                     if (c.Provider == provider && c.ProviderConnectionPoint == providerConnectionPoint) {
1290                         if (throwOnError) {
1291                             throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_Duplicate, providerConnectionPoint.ID, provider.ID));
1292                         }
1293                         else {
1294                             return false;
1295                         }
1296                     }
1297                 }
1298             }
1299 
1300             if (!consumerConnectionPoint.AllowsMultipleConnections) {
1301                 foreach (WebPartConnection c in Connections) {
1302                     if (c.Consumer == consumer && c.ConsumerConnectionPoint == consumerConnectionPoint) {
1303                         if (throwOnError) {
1304                             throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_Duplicate, consumerConnectionPoint.ID, consumer.ID));
1305                         }
1306                         else {
1307                             return false;
1308                         }
1309                     }
1310                 }
1311             }
1312 
1313             if (transformer == null) {
1314                 if (providerConnectionPoint.InterfaceType != consumerConnectionPoint.InterfaceType) {
1315                     if (throwOnError) {
1316                         throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_NoCommonInterface,
1317                             new string[] {providerConnectionPoint.DisplayName, provider.ID,
1318                                 consumerConnectionPoint.DisplayName, consumer.ID}));
1319                     }
1320                     else {
1321                         return false;
1322                     }
1323                 }
1324 
1325                 ConnectionInterfaceCollection secondaryInterfaces = providerConnectionPoint.GetSecondaryInterfaces(providerControl);
1326                 if (!consumerConnectionPoint.SupportsConnection(consumerControl, secondaryInterfaces)) {
1327                     if (throwOnError) {
1328                         throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_IncompatibleSecondaryInterfaces, new string[] {
1329                                 consumerConnectionPoint.DisplayName, consumer.ID,
1330                                 providerConnectionPoint.DisplayName, provider.ID}));
1331                     }
1332                     else {
1333                         return false;
1334                     }
1335                 }
1336             }
1337             else {
1338                 Type transformerType = transformer.GetType();
1339 
1340                 if (!AvailableTransformers.Contains(transformerType)) {
1341                     throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_TransformerNotAvailable, transformerType.FullName));
1342                 }
1343 
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) {
1353                     if (throwOnError) {
1354                         throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_IncompatibleProviderTransformer,
1355                             providerConnectionPoint.DisplayName, provider.ID, transformerType.FullName));
1356                     }
1357                     else {
1358                         return false;
1359                     }
1360                 }
1361                 if (transformerProviderType != consumerConnectionPoint.InterfaceType) {
1362                     if (throwOnError) {
1363                         throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_IncompatibleConsumerTransformer,
1364                             transformerType.FullName, consumerConnectionPoint.DisplayName, consumer.ID));
1365                     }
1366                     else {
1367                         return false;
1368                     }
1369                 }
1370 
1371                 // A transformer never provides any secondary interfaces
1372                 if (!consumerConnectionPoint.SupportsConnection(consumerControl, ConnectionInterfaceCollection.Empty)) {
1373                     if (throwOnError) {
1374                         throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_ConsumerRequiresSecondaryInterfaces,
1375                             consumerConnectionPoint.DisplayName, consumer.ID));
1376                     }
1377                     else {
1378                         return false;
1379                     }
1380                 }
1381 
1382             }
1383 
1384             return true;
1385         }
1386 
CloseWebPart(WebPart webPart)1387         public void CloseWebPart(WebPart webPart) {
1388             CloseOrDeleteWebPart(webPart, /* delete */ false);
1389         }
1390 
CloseOrDeleteWebPart(WebPart webPart, bool delete)1391         private void CloseOrDeleteWebPart(WebPart webPart, bool delete) {
1392             Personalization.EnsureEnabled(/* ensureModifiable */ true);
1393 
1394             if (webPart == null) {
1395                 throw new ArgumentNullException("webPart");
1396             }
1397             if (!Controls.Contains(webPart)) {
1398                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
1399             }
1400 
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");
1406             }
1407 
1408             if (delete) {
1409                 if (webPart.IsStatic) {
1410                     // Can't delete static parts
1411                     throw new ArgumentException(SR.GetString(SR.WebPartManager_CantDeleteStatic), "webPart");
1412                 }
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");
1416                 }
1417             }
1418 
1419             WebPartCancelEventArgs ce = new WebPartCancelEventArgs(webPart);
1420             if (delete) {
1421                 OnWebPartDeleting(ce);
1422             }
1423             else {
1424                 OnWebPartClosing(ce);
1425             }
1426             if (_allowEventCancellation && ce.Cancel) {
1427                 return;
1428             }
1429 
1430             if ((DisplayMode == ConnectDisplayMode) && (webPart == SelectedWebPart)) {
1431                 EndWebPartConnecting();
1432                 if (SelectedWebPart != null) {
1433                     // The ConnectModeChange was cancelled
1434                     return;
1435                 }
1436             }
1437 
1438             // VSWhidbey 77768
1439             if ((DisplayMode == EditDisplayMode) && (webPart == SelectedWebPart)) {
1440                 EndWebPartEditing();
1441                 if (SelectedWebPart != null) {
1442                     // The EditModeChange was cancelled
1443                     return;
1444                 }
1445             }
1446 
1447             if (delete) {
1448                 Internals.CallOnDeleting(webPart);
1449             }
1450             else {
1451                 Internals.CallOnClosing(webPart);
1452             }
1453 
1454 #if DEBUG
1455             WebPartZoneBase zone = webPart.Zone;
1456 #endif
1457 
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);
1462             }
1463 
1464             DisconnectWebPart(webPart);
1465 
1466             if (delete) {
1467                 Internals.RemoveWebPart(webPart);
1468 
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));
1472             }
1473             else {
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));
1477             }
1478 
1479 #if DEBUG
1480             if (zone != null) {
1481                 CheckPartZoneIndexes(zone);
1482             }
1483 #endif
1484         }
1485 
ConnectionsToActivate()1486         private WebPartConnection[] ConnectionsToActivate() {
1487             // PERF: We could implement this with a sorted list to simplify the code
1488 
1489             ArrayList connectionsToActivate = new ArrayList();
1490 
1491             // Contains the connection IDs we have already seen
1492             HybridDictionary connectionIDs = new HybridDictionary(true /* caseInsensitive */);
1493 
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);
1499             }
1500 
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) {
1506                     continue;
1507                 }
1508 
1509                 ArrayList connectionsToDelete = new ArrayList();
1510                 foreach (WebPartConnection otherConnection in connectionsToActivate) {
1511                     if (connection == otherConnection) {
1512                         continue;
1513                     }
1514 
1515                     if (otherConnection.IsShared && connection.ConflictsWith(otherConnection)) {
1516                         // Delete shared connection.
1517                         connectionsToDelete.Add(otherConnection);
1518                     }
1519                 }
1520 
1521                 foreach (WebPartConnection connectionToDelete in connectionsToDelete) {
1522                     DisconnectWebParts(connectionToDelete);
1523                     connectionsToActivate.Remove(connectionToDelete);
1524                 }
1525             }
1526 
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) {
1531                     continue;
1532                 }
1533 
1534                 ArrayList connectionsToDelete = new ArrayList();
1535                 foreach (WebPartConnection otherConnection in connectionsToActivate) {
1536                     if (connection == otherConnection) {
1537                         continue;
1538                     }
1539 
1540                     if (otherConnection.IsStatic && connection.ConflictsWith(otherConnection)) {
1541                         // Delete static connection.
1542                         connectionsToDelete.Add(otherConnection);
1543                     }
1544                 }
1545 
1546                 foreach (WebPartConnection connectionToDelete in connectionsToDelete) {
1547                     DisconnectWebParts(connectionToDelete);
1548                     connectionsToActivate.Remove(connectionToDelete);
1549                 }
1550             }
1551 
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;
1558 
1559                 foreach (WebPartConnection otherConnection in connectionsToActivate) {
1560                     if (connection == otherConnection) {
1561                         continue;
1562                     }
1563 
1564                     if (connection.ConflictsWithConsumer(otherConnection)) {
1565                         connection.Consumer.SetConnectErrorMessage(SR.GetString(SR.WebPartConnection_Duplicate, connection.ConsumerConnectionPoint.DisplayName,
1566                                 connection.Consumer.DisplayTitle));
1567                         hasConflict = true;
1568                     }
1569 
1570                     if (connection.ConflictsWithProvider(otherConnection)) {
1571                         connection.Consumer.SetConnectErrorMessage(SR.GetString(SR.WebPartConnection_Duplicate, connection.ProviderConnectionPoint.DisplayName,
1572                                 connection.Provider.DisplayTitle));
1573                         hasConflict = true;
1574                     }
1575                 }
1576 
1577                 if (!hasConflict) {
1578                     finalConnectionsToActivate.Add(connection);
1579                 }
1580             }
1581 
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);
1585 
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);
1590 
1591             return (WebPartConnection[])finalConnectionsToActivate.ToArray(typeof(WebPartConnection));
1592         }
1593 
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.
ConnectionsToActivateHelper(WebPartConnection connection, IDictionary connectionIDs, ArrayList connectionsToActivate)1596         private void ConnectionsToActivateHelper(WebPartConnection connection, IDictionary connectionIDs,
1597                                                  ArrayList connectionsToActivate) {
1598             string connectionID = connection.ID;
1599 
1600             if (String.IsNullOrEmpty(connectionID)) {
1601                 throw new InvalidOperationException(SR.GetString(SR.WebPartConnection_NoID));
1602             }
1603 
1604             if (connectionIDs.Contains(connectionID)) {
1605                 throw new InvalidOperationException(
1606                     SR.GetString(SR.WebPartManager_DuplicateConnectionID, connectionID));
1607             }
1608             connectionIDs.Add(connectionID, null);
1609 
1610             if (connection.Deleted) {
1611                 return;
1612             }
1613 
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));
1619                 }
1620                 else {
1621                     // Silently delete the connection, since this is a valid runtime scenario.
1622                     // A connected web part may have been deleted.
1623                     DisconnectWebParts(connection);
1624                     return;
1625                 }
1626             }
1627 
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));
1633                 }
1634                 else {
1635                     // Silently delete the connection, since this is a valid runtime scenario.
1636                     // A connected web part may have been deleted.
1637                     DisconnectWebParts(connection);
1638                     return;
1639                 }
1640             }
1641 
1642             // Do not activate connections involving ProxyWebParts
1643             if (providerWebPart is ProxyWebPart || consumerWebPart is ProxyWebPart) {
1644                 return;
1645             }
1646 
1647             Control providerControl = providerWebPart.ToControl();
1648             Control consumerControl = consumerWebPart.ToControl();
1649 
1650             // Cannot connect a WebPart to itself
1651             if (providerControl == consumerControl) {
1652                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_CantConnectToSelf));
1653             }
1654 
1655             ProviderConnectionPoint providerConnectionPoint = connection.ProviderConnectionPoint;
1656             if (providerConnectionPoint == null) {
1657                 consumerWebPart.SetConnectErrorMessage(SR.GetString(SR.WebPartConnection_NoProviderConnectionPoint, connection.ProviderConnectionPointID,
1658                     providerWebPart.DisplayTitle));
1659                 return;
1660             }
1661             // Don't need to check that providerConnectionPoint is enabled, since this will be checked
1662             // in WebPartConnection.Activate().
1663 
1664             ConsumerConnectionPoint consumerConnectionPoint = connection.ConsumerConnectionPoint;
1665             if (consumerConnectionPoint == null) {
1666                 consumerWebPart.SetConnectErrorMessage(SR.GetString(SR.WebPartConnection_NoConsumerConnectionPoint, connection.ConsumerConnectionPointID,
1667                     consumerWebPart.DisplayTitle));
1668                 return;
1669             }
1670             // Don't need to check that consumer ConnectionPoint is enabled, since this will be checked
1671             // in WebPartConnection.Activate().
1672 
1673             connectionsToActivate.Add(connection);
1674         }
1675 
ConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint, WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint)1676         public WebPartConnection ConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint,
1677                                                  WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint) {
1678             return ConnectWebParts(provider, providerConnectionPoint, consumer, consumerConnectionPoint, null);
1679         }
1680 
ConnectWebParts(WebPart provider, ProviderConnectionPoint providerConnectionPoint, WebPart consumer, ConsumerConnectionPoint consumerConnectionPoint, WebPartTransformer transformer)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);
1686 
1687             if (DynamicConnections.IsReadOnly) {
1688                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_ConnectTooLate));
1689             }
1690 
1691             WebPartConnectionsCancelEventArgs ce = new WebPartConnectionsCancelEventArgs(
1692                 provider, providerConnectionPoint, consumer, consumerConnectionPoint);
1693             OnWebPartsConnecting(ce);
1694             if (_allowEventCancellation && ce.Cancel) {
1695                 return null;
1696             }
1697 
1698             Control providerControl = provider.ToControl();
1699             Control consumerControl = consumer.ToControl();
1700 
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;
1707 
1708             if (transformer != null) {
1709                 Internals.SetTransformer(connection, transformer);
1710             }
1711 
1712             Internals.SetIsShared(connection, Personalization.Scope == PersonalizationScope.Shared);
1713             Internals.SetIsStatic(connection, false);
1714 
1715             DynamicConnections.Add(connection);
1716             _hasDataChanged = true;
1717 
1718             OnWebPartsConnected(new WebPartConnectionsEventArgs(provider, providerConnectionPoint,
1719                                                                 consumer, consumerConnectionPoint, connection));
1720 
1721             return connection;
1722         }
1723 
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.
CopyWebPart(WebPart webPart)1729         protected virtual WebPart CopyWebPart(WebPart webPart) {
1730             WebPart newWebPart;
1731 
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);
1739 
1740                 newWebPart = CreateWebPart(newChildControl);
1741             }
1742             else {
1743                 VerifyType(webPart);
1744                 newWebPart = (WebPart)Internals.CreateObjectFromType(webPart.GetType());
1745             }
1746 
1747             newWebPart.ID = CreateDynamicWebPartID(webPart.GetType());
1748 
1749             return newWebPart;
1750         }
1751 
CreateAvailableTransformers()1752         protected virtual TransformerTypeCollection CreateAvailableTransformers() {
1753             TransformerTypeCollection availableTransformers = new TransformerTypeCollection();
1754 
1755             WebPartsSection configSection = RuntimeConfig.GetConfig().WebParts;
1756 
1757             IDictionary transformers = configSection.Transformers.GetTransformerEntries();
1758 
1759             foreach (Type type in transformers.Values) {
1760                 availableTransformers.Add(type);
1761             }
1762 
1763             return availableTransformers;
1764         }
1765 
1766         // Returns an array of ICollection objects.  The first is the ConsumerConnectionPoints, the
1767         // second is the ProviderConnectionPoints.
CreateConnectionPoints(Type type)1768         private static ICollection[] CreateConnectionPoints(Type type) {
1769             ArrayList consumerConnectionPoints = new ArrayList();
1770             ArrayList providerConnectionPoints = new ArrayList();
1771 
1772             MethodInfo[] methods = type.GetMethods(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
1773             foreach (MethodInfo method in methods) {
1774 
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;
1785                     }
1786 
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);
1797                         }
1798                         else {
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);
1802                         }
1803                         consumerConnectionPoints.Add(connectionPoint);
1804                     }
1805                     else {
1806                         throw new InvalidOperationException(SR.GetString(SR.WebPartManager_InvalidConsumerSignature, method.Name, type.FullName));
1807                     }
1808                 }
1809 
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);
1827                         }
1828                         else {
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);
1832                         }
1833                         providerConnectionPoints.Add(connectionPoint);
1834                     }
1835                     else {
1836                         throw new InvalidOperationException(SR.GetString(SR.WebPartManager_InvalidProviderSignature, method.Name, type.FullName));
1837                     }
1838                 }
1839             }
1840 
1841             return new ICollection[] { new ConsumerConnectionPointCollection(consumerConnectionPoints),
1842                 new ProviderConnectionPointCollection(providerConnectionPoints) };
1843         }
1844 
CreateControlCollection()1845         protected sealed override ControlCollection CreateControlCollection() {
1846             return new WebPartManagerControlCollection(this);
1847         }
1848 
1849         /// <devdoc>
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.
1852         /// </devdoc>
CreateDisplayModes()1853         protected virtual WebPartDisplayModeCollection CreateDisplayModes() {
1854             WebPartDisplayModeCollection displayModes = new WebPartDisplayModeCollection();
1855 
1856             displayModes.Add(BrowseDisplayMode);
1857             displayModes.Add(CatalogDisplayMode);
1858             displayModes.Add(DesignDisplayMode);
1859             displayModes.Add(EditDisplayMode);
1860             displayModes.Add(ConnectDisplayMode);
1861 
1862             return displayModes;
1863         }
1864 
CreateDisplayTitle(string title, WebPart webPart, int count)1865         private string CreateDisplayTitle(string title, WebPart webPart, int count) {
1866             string displayTitle = title;
1867 
1868             if (webPart.Hidden) {
1869                 displayTitle = SR.GetString(SR.WebPart_HiddenFormatString, displayTitle);
1870             }
1871 
1872             if (webPart is ErrorWebPart) {
1873                 displayTitle = SR.GetString(SR.WebPart_ErrorFormatString, displayTitle);
1874             }
1875 
1876             if (count != 0) {
1877                 if (count < displayTitleSuffix.Length) {
1878                     displayTitle += displayTitleSuffix[count];
1879                 }
1880                 else {
1881                     displayTitle += " [" + count.ToString(CultureInfo.CurrentCulture) + "]";
1882                 }
1883             }
1884 
1885             return displayTitle;
1886         }
1887 
CreateDisplayTitles()1888         private IDictionary CreateDisplayTitles() {
1889             Hashtable displayTitles = new Hashtable();
1890 
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);
1896                 }
1897 
1898                 if (part is UnauthorizedWebPart) {
1899                     displayTitles[part] = title;
1900                     continue;
1901                 }
1902 
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);
1908                 }
1909                 else {
1910                     int count = parts.Count;
1911                     if (count == 1) {
1912                         WebPart firstPart = (WebPart)parts[0];
1913                         displayTitles[firstPart] = CreateDisplayTitle(title, firstPart, 1);
1914                     }
1915                     displayTitles[part] = CreateDisplayTitle(title, part, count + 1);
1916                 }
1917 
1918                 parts.Add(part);
1919             }
1920 
1921             return displayTitles;
1922         }
1923 
CreateDynamicConnectionID()1924         protected virtual string CreateDynamicConnectionID() {
1925             Debug.Assert(Personalization.IsModifiable);
1926             //
1927             int guidHash = Math.Abs(Guid.NewGuid().GetHashCode());
1928             return DynamicConnectionIDPrefix + guidHash.ToString(CultureInfo.InvariantCulture);
1929         }
1930 
CreateDynamicWebPartID(Type webPartType)1931         protected virtual string CreateDynamicWebPartID(Type webPartType) {
1932             if (webPartType == null) {
1933                 throw new ArgumentNullException("webPartType");
1934             }
1935 
1936             Debug.Assert(Personalization.IsModifiable);
1937 
1938             //
1939 
1940             int guidHash = Math.Abs(Guid.NewGuid().GetHashCode());
1941             string id = DynamicWebPartIDPrefix + guidHash.ToString(CultureInfo.InvariantCulture);
1942 
1943             if (Page != null && Page.Trace.IsEnabled) {
1944                 id += webPartType.Name;
1945             }
1946 
1947             return id;
1948         }
1949 
CreateErrorWebPart(string originalID, string originalTypeName, string originalPath, string genericWebPartID, string errorMessage)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;
1956         }
1957 
1958         /// <devdoc>
1959         /// </devdoc>
CreatePersonalization()1960         protected virtual WebPartPersonalization CreatePersonalization() {
1961             return new WebPartPersonalization(this);
1962         }
1963 
1964         /// <devdoc>
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.
1968         /// </devdoc>
CreateWebPart(Control control)1969         public virtual GenericWebPart CreateWebPart(Control control) {
1970             return CreateWebPartStatic(control);
1971         }
1972 
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.
CreateWebPartStatic(Control control)1976         internal static GenericWebPart CreateWebPartStatic(Control control) {
1977             GenericWebPart genericWebPart = new GenericWebPart(control);
1978 
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();
1985 
1986             return genericWebPart;
1987         }
1988 
DeleteWebPart(WebPart webPart)1989         public void DeleteWebPart(WebPart webPart) {
1990             CloseOrDeleteWebPart(webPart, /* delete */ true);
1991         }
1992 
1993         // Disconnects all connections involving the Web Part
DisconnectWebPart(WebPart webPart)1994         protected virtual void DisconnectWebPart(WebPart webPart) {
1995             try {
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);
2002                     }
2003                 }
2004             }
2005             finally {
2006                 _allowEventCancellation = true;
2007             }
2008         }
2009 
DisconnectWebParts(WebPartConnection connection)2010         public virtual void DisconnectWebParts(WebPartConnection connection) {
2011             Personalization.EnsureEnabled(/* ensureModifiable */ true);
2012 
2013             if (connection == null) {
2014                 throw new ArgumentNullException("connection");
2015             }
2016 
2017             Debug.Assert(!(StaticConnections.Contains(connection) && DynamicConnections.Contains(connection)));
2018 
2019             WebPart provider = connection.Provider;
2020             ProviderConnectionPoint providerConnectionPoint = connection.ProviderConnectionPoint;
2021             WebPart consumer = connection.Consumer;
2022             ConsumerConnectionPoint consumerConnectionPoint = connection.ConsumerConnectionPoint;
2023 
2024             WebPartConnectionsCancelEventArgs ce = new WebPartConnectionsCancelEventArgs(
2025                 provider, providerConnectionPoint, consumer, consumerConnectionPoint, connection);
2026             OnWebPartsDisconnecting(ce);
2027             if (_allowEventCancellation && ce.Cancel) {
2028                 return;
2029             }
2030 
2031             WebPartConnectionsEventArgs eventArgs = new WebPartConnectionsEventArgs(
2032                 provider, providerConnectionPoint, consumer, consumerConnectionPoint);
2033 
2034             if (StaticConnections.Contains(connection)) {
2035                 if (StaticConnections.IsReadOnly) {
2036                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DisconnectTooLate));
2037                 }
2038                 if (Internals.ConnectionDeleted(connection)) {
2039                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_AlreadyDisconnected));
2040                 }
2041                 Internals.DeleteConnection(connection);
2042                 _hasDataChanged = true;
2043                 OnWebPartsDisconnected(eventArgs);
2044             }
2045             else if (DynamicConnections.Contains(connection)) {
2046                 if (DynamicConnections.IsReadOnly) {
2047                     throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DisconnectTooLate));
2048                 }
2049 
2050                 if (ShouldRemoveConnection(connection)) {
2051                     // Unshared dynamic connection should never be disabled
2052                     Debug.Assert(!Internals.ConnectionDeleted(connection));
2053                     DynamicConnections.Remove(connection);
2054                 }
2055                 else {
2056                     if (Internals.ConnectionDeleted(connection)) {
2057                         throw new InvalidOperationException(SR.GetString(SR.WebPartManager_AlreadyDisconnected));
2058                     }
2059                     Internals.DeleteConnection(connection);
2060                 }
2061                 _hasDataChanged = true;
2062                 OnWebPartsDisconnected(eventArgs);
2063             }
2064             else {
2065                 throw new ArgumentException(SR.GetString(SR.WebPartManager_UnknownConnection), "connection");
2066             }
2067         }
2068 
EndWebPartConnecting()2069         public virtual void EndWebPartConnecting() {
2070             Personalization.EnsureEnabled(/* ensureModifiable */ true);
2071 
2072             WebPart selectedWebPart = SelectedWebPart;
2073 
2074             if (selectedWebPart == null) {
2075                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoSelectedWebPartConnect));
2076             }
2077 
2078             WebPartCancelEventArgs ce = new WebPartCancelEventArgs(selectedWebPart);
2079             OnSelectedWebPartChanging(ce);
2080 
2081             if (_allowEventCancellation && ce.Cancel) {
2082                 return;
2083             }
2084 
2085             SetSelectedWebPart(null);
2086 
2087             Internals.CallOnConnectModeChanged(selectedWebPart);
2088 
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));
2092         }
2093 
EndWebPartEditing()2094         public virtual void EndWebPartEditing() {
2095             Personalization.EnsureEnabled(/* ensureModifiable */ true);
2096 
2097             WebPart selectedWebPart = SelectedWebPart;
2098 
2099             if (selectedWebPart == null) {
2100                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoSelectedWebPartEdit));
2101             }
2102 
2103             WebPartCancelEventArgs ce = new WebPartCancelEventArgs(selectedWebPart);
2104             OnSelectedWebPartChanging(ce);
2105 
2106             if (_allowEventCancellation && ce.Cancel) {
2107                 return;
2108             }
2109 
2110             SetSelectedWebPart(null);
2111 
2112             Internals.CallOnEditModeChanged(selectedWebPart);
2113 
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));
2117         }
2118 
ExportWebPart(WebPart webPart, XmlWriter writer)2119         public virtual void ExportWebPart(WebPart webPart, XmlWriter writer) {
2120 //            Personalization.EnsureEnabled(/* ensureModifiable */ false);
2121 
2122             if (webPart == null) {
2123                 throw new ArgumentNullException("webPart");
2124             }
2125             if (!Controls.Contains(webPart)) {
2126                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
2127             }
2128 
2129             if (writer == null) {
2130                 throw new ArgumentNullException("writer");
2131             }
2132             if (webPart.ExportMode == WebPartExportMode.None) {
2133                 throw new ArgumentException(SR.GetString(SR.WebPartManager_PartNotExportable), "webPart");
2134             }
2135             bool excludeSensitive = (webPart.ExportMode == WebPartExportMode.NonSensitiveData &&
2136                 !(Personalization.Scope == PersonalizationScope.Shared));
2137 
2138             // Write the root elements
2139             writer.WriteStartElement(ExportRootElement);
2140             writer.WriteStartElement(ExportPartElement);
2141             writer.WriteAttributeString(ExportPartNamespaceAttribute, ExportPartNamespaceValue);
2142             // Write metadata
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);
2149             }
2150             else {
2151                 writer.WriteAttributeString(ExportTypeNameAttribute, WebPartUtil.SerializeType(control.GetType()));
2152             }
2153             writer.WriteEndElement(); //type
2154             writer.WriteElementString(ExportErrorMessageElement, webPart.ImportErrorMessage);
2155             writer.WriteEndElement(); //metadata
2156             // Write the data
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);
2160 
2161             writer.WriteStartElement(ExportPropertiesElement);
2162 
2163             // Special case GenericWebPart
2164             GenericWebPart genericWebPart = webPart as GenericWebPart;
2165 
2166             if (genericWebPart != null) {
2167 
2168                 // Export IPersonalizable user control data first
2169                 ExportIPersonalizable(writer, control, excludeSensitive);
2170 
2171                 IDictionary controlData = PersonalizableAttribute.GetPersonalizablePropertyValues(control,
2172                                                                                                   PersonalizationScope.Shared,
2173                                                                                                   excludeSensitive);
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);
2180             }
2181             else {
2182                 // Export IPersonalizable part data first
2183                 ExportIPersonalizable(writer, webPart, excludeSensitive);
2184                 ExportToWriter(propBag, writer);
2185             }
2186             writer.WriteEndElement(); //properties or genericWebPartProperties
2187             writer.WriteEndElement(); //data
2188             writer.WriteEndElement(); //webpart
2189             writer.WriteEndElement(); //webparts
2190         }
2191 
ExportIPersonalizable(XmlWriter writer, Control control, bool excludeSensitive)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
2201                 }
2202             }
2203         }
2204 
ExportProperty(XmlWriter writer, string name, string value, Type type, PersonalizationScope scope, bool isIPersonalizable)2205         private static void ExportProperty(XmlWriter writer, string name, string value, Type type,
2206             PersonalizationScope scope, bool isIPersonalizable) {
2207 
2208             writer.WriteStartElement(ExportPropertyElement);
2209             writer.WriteAttributeString(ExportPropertyNameAttribute, name);
2210             writer.WriteAttributeString(ExportPropertyTypeAttribute, GetExportName(type));
2211             if (isIPersonalizable) {
2212                 writer.WriteAttributeString(ExportPropertyScopeAttribute, scope.ToString());
2213             }
2214             if (value == null) {
2215                 writer.WriteAttributeString(ExportPropertyNullAttribute, "true");
2216             }
2217             else {
2218                 writer.WriteString(value);
2219             }
2220             writer.WriteEndElement(); //property
2221         }
2222 
ExportToWriter(IDictionary propBag, XmlWriter writer)2223         private void ExportToWriter(IDictionary propBag, XmlWriter writer) {
2224             ExportToWriter(propBag, writer, false, false);
2225         }
2226 
ExportToWriter(IDictionary propBag, XmlWriter writer, bool isIPersonalizable, bool excludeSensitive)2227         private void ExportToWriter(IDictionary propBag,
2228                                     XmlWriter writer,
2229                                     bool isIPersonalizable,
2230                                     bool excludeSensitive) {
2231             // We only honor excludeSensitive if isIpersonalizable is true.
2232             Debug.Assert((!excludeSensitive) || isIPersonalizable);
2233 
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) {
2238                     continue;
2239                 }
2240 
2241                 PropertyInfo pi = null;
2242                 object val = 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;
2249                     val = data.Second;
2250                 }
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)) {
2256 
2257                         val = personalizationEntry.Value;
2258                         scope = personalizationEntry.Scope;
2259                     }
2260                     if (excludeSensitive && personalizationEntry.IsSensitive) {
2261                         continue;
2262                     }
2263                 }
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)));
2266 
2267                 string exportString;
2268                 if (ShouldExportProperty(pi, valType, val, out exportString)) {
2269                     ExportProperty(writer, name, exportString, valType, scope, isIPersonalizable);
2270                 }
2271             }
2272         }
2273 
2274         [
2275         EditorBrowsable(EditorBrowsableState.Never),
2276         ]
Focus()2277         public override void Focus() {
2278             throw new NotSupportedException(SR.GetString(SR.NoFocusSupport, this.GetType().Name));
2279         }
2280 
2281         /// <devdoc>
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.
2285         /// </devdoc>
GetAllWebPartsForZone(WebPartZoneBase zone)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;
2298                             }
2299                             partsForZone.Add(part, null);
2300                         }
2301                     }
2302                 }
2303             }
2304 
2305             SortedList parts = (SortedList)_partsForZone[zone.ID];
2306             if (parts == null) {
2307                 parts = new SortedList();
2308             }
2309 
2310             return parts.GetKeyList();
2311         }
2312 
GetConnectionPoints(Type type)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());
2320             }
2321 
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);
2324 
2325             ICollection[] connectionPoints = (ICollection[])ConnectionPointsCache[connectionPointKey];
2326             if (connectionPoints == null) {
2327                 connectionPoints = CreateConnectionPoints(type);
2328                 ConnectionPointsCache[connectionPointKey] = connectionPoints;
2329             }
2330 
2331             return connectionPoints;
2332         }
2333 
GetConsumerConnectionPoint(WebPart webPart, string connectionPointID)2334         internal ConsumerConnectionPoint GetConsumerConnectionPoint(WebPart webPart, string connectionPointID) {
2335             ConsumerConnectionPointCollection points = GetConsumerConnectionPoints(webPart);
2336             if (points != null && points.Count > 0) {
2337                 return points[connectionPointID];
2338             }
2339             else {
2340                 return null;
2341             }
2342         }
2343 
GetConsumerConnectionPoints(WebPart webPart)2344         public virtual ConsumerConnectionPointCollection GetConsumerConnectionPoints(WebPart webPart) {
2345             if (webPart == null) {
2346                 throw new ArgumentNullException("webPart");
2347             }
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.
2351 
2352             return GetConsumerConnectionPoints(webPart.ToControl().GetType());
2353         }
2354 
GetConsumerConnectionPoints(Type type)2355         private static ConsumerConnectionPointCollection GetConsumerConnectionPoints(Type type) {
2356             ICollection[] connectionPoints = GetConnectionPoints(type);
2357             return (ConsumerConnectionPointCollection)connectionPoints[0];
2358         }
2359 
GetCurrentWebPartManager(Page page)2360         public static WebPartManager GetCurrentWebPartManager(Page page) {
2361             if (page == null) {
2362                 throw new ArgumentNullException("page");
2363             }
2364 
2365             return page.Items[typeof(WebPartManager)] as WebPartManager;
2366         }
2367 
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.
GetDisplayTitle(WebPart webPart)2373         protected internal virtual string GetDisplayTitle(WebPart webPart) {
2374             if (webPart == null) {
2375                 throw new ArgumentNullException("webPart");
2376             }
2377             if (!Controls.Contains(webPart)) {
2378                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
2379             }
2380 
2381             if (!_allowCreateDisplayTitles) {
2382                 return String.Empty;
2383             }
2384 
2385             if (_displayTitles == null) {
2386                 _displayTitles = CreateDisplayTitles();
2387             }
2388 
2389             string displayTitle = (string)_displayTitles[webPart];
2390             Debug.Assert(!String.IsNullOrEmpty(displayTitle));
2391             return displayTitle;
2392         }
2393 
GetEnabledConnectionPoints(ICollection connectionPoints, WebPart webPart)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);
2400                 }
2401             }
2402             return enabledPoints;
2403         }
2404 
GetEnabledConsumerConnectionPoints(WebPart webPart)2405         internal ConsumerConnectionPointCollection GetEnabledConsumerConnectionPoints(WebPart webPart) {
2406             ICollection enabledPoints = GetEnabledConnectionPoints(GetConsumerConnectionPoints(webPart), webPart);
2407             return new ConsumerConnectionPointCollection(enabledPoints);
2408         }
2409 
GetEnabledProviderConnectionPoints(WebPart webPart)2410         internal ProviderConnectionPointCollection GetEnabledProviderConnectionPoints(WebPart webPart) {
2411             ICollection enabledPoints = GetEnabledConnectionPoints(GetProviderConnectionPoints(webPart), webPart);
2412             return new ProviderConnectionPointCollection(enabledPoints);
2413         }
2414 
GetExportUrl(WebPart webPart)2415         public string GetExportUrl(WebPart webPart) {
2416             string personalizationScope =
2417                 (Personalization.Scope == PersonalizationScope.Shared) ? "&scope=shared" : String.Empty;
2418             string queryString = Page.Request.QueryStringText;
2419 
2420             return Page.Request.FilePath + "?" + Page.WebPartExportID + "=true&webPart=" +
2421                 HttpUtility.UrlEncode(webPart.ID) +
2422                 (!String.IsNullOrEmpty(queryString) ?
2423                     "&query=" + HttpUtility.UrlEncode(queryString) :
2424                     String.Empty) +
2425                 personalizationScope;
2426         }
2427 
GetExportType(string name)2428         private static Type GetExportType(string name) {
2429             switch (name) {
2430                 case ExportTypeString:
2431                     return typeof(string);
2432                 case ExportTypeInt:
2433                     return typeof(int);
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);
2460                 default:
2461                     return WebPartUtil.DeserializeType(name, false);
2462             }
2463         }
2464 
GetExportName(Type type)2465         private static string GetExportName(Type type) {
2466             if (type == typeof(string)) {
2467                 return ExportTypeString;
2468             }
2469             else if (type == typeof(int)) {
2470                 return ExportTypeInt;
2471             }
2472             else if (type == typeof(bool)) {
2473                 return ExportTypeBool;
2474             }
2475             else if (type == typeof(double)) {
2476                 return ExportTypeDouble;
2477             }
2478             else if (type == typeof(Single)) {
2479                 return ExportTypeSingle;
2480             }
2481             else if (type == typeof(DateTime)) {
2482                 return ExportTypeDateTime;
2483             }
2484             else if (type == typeof(Color)) {
2485                 return ExportTypeColor;
2486             }
2487             else if (type == typeof(Unit)) {
2488                 return ExportTypeUnit;
2489             }
2490             else if (type == typeof(FontSize)) {
2491                 return ExportTypeFontSize;
2492             }
2493             else if (type == typeof(ContentDirection)) {
2494                 return ExportTypeDirection;
2495             }
2496             else if (type == typeof(WebPartHelpMode)) {
2497                 return ExportTypeHelpMode;
2498             }
2499             else if (type == typeof(PartChromeState)) {
2500                 return ExportTypeChromeState;
2501             }
2502             else if (type == typeof(PartChromeType)) {
2503                 return ExportTypeChromeType;
2504             }
2505             else if (type == typeof(WebPartExportMode)) {
2506                 return ExportTypeExportMode;
2507             }
2508             else if (type == typeof(object)) {
2509                 return ExportTypeObject;
2510             }
2511             else {
2512                 return type.AssemblyQualifiedName;
2513             }
2514         }
2515 
2516         /// <devdoc>
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.
2519         /// </devdoc>
GetGenericWebPart(Control control)2520         public GenericWebPart GetGenericWebPart(Control control) {
2521              if (control == null) {
2522                  throw new ArgumentNullException("control");
2523              }
2524 
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;
2530              }
2531              else {
2532                  foreach (WebPart part in Controls) {
2533                      GenericWebPart genericPart = part as GenericWebPart;
2534                      if (genericPart != null && genericPart.ChildControl == control) {
2535                          return genericPart;
2536                      }
2537                  }
2538              }
2539 
2540              return null;
2541         }
2542 
GetProviderConnectionPoint(WebPart webPart, string connectionPointID)2543         internal ProviderConnectionPoint GetProviderConnectionPoint(WebPart webPart, string connectionPointID) {
2544             ProviderConnectionPointCollection points = GetProviderConnectionPoints(webPart);
2545             if (points != null && points.Count > 0) {
2546                 return points[connectionPointID];
2547             }
2548             else {
2549                 return null;
2550             }
2551         }
2552 
GetProviderConnectionPoints(WebPart webPart)2553         public virtual ProviderConnectionPointCollection GetProviderConnectionPoints(WebPart webPart) {
2554             if (webPart == null) {
2555                 throw new ArgumentNullException("webPart");
2556             }
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.
2560 
2561             return GetProviderConnectionPoints(webPart.ToControl().GetType());
2562         }
2563 
GetProviderConnectionPoints(Type type)2564         private static ProviderConnectionPointCollection GetProviderConnectionPoints(Type type) {
2565             ICollection[] connectionPoints = GetConnectionPoints(type);
2566             return (ProviderConnectionPointCollection)connectionPoints[1];
2567         }
2568 
2569         /// <devdoc>
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)
2573         /// </devdoc>
GetWebPartsForZone(WebPartZoneBase zone)2574         internal WebPartCollection GetWebPartsForZone(WebPartZoneBase zone) {
2575             if (zone == null) {
2576                 throw new ArgumentNullException("zone");
2577             }
2578             if (_webPartZones.Contains(zone) == false) {
2579                 throw new ArgumentException(SR.GetString(SR.WebPartManager_MustRegister), "zone");
2580             }
2581 
2582             IList allWebPartsForZone = GetAllWebPartsForZone(zone);
2583             WebPartCollection webParts = new WebPartCollection();
2584 
2585             if (allWebPartsForZone.Count > 0) {
2586                 foreach (WebPart part in allWebPartsForZone) {
2587                     if (ShouldRenderWebPartInZone(part, zone)) {
2588                         webParts.Add(part);
2589                     }
2590                 }
2591             }
2592 
2593             return webParts;
2594         }
2595 
2596         /// <devdoc>
2597         /// If the WebPart is a consumer on the given connection point, returns the corresponding connection.
2598         /// Else, returns null.
2599         /// </devdoc>
GetConnectionForConsumer(WebPart consumer, ConsumerConnectionPoint connectionPoint)2600         internal WebPartConnection GetConnectionForConsumer(WebPart consumer, ConsumerConnectionPoint connectionPoint) {
2601             ConsumerConnectionPoint actualConnectionPoint = connectionPoint;
2602             //
2603             if (connectionPoint == null) {
2604                 actualConnectionPoint = GetConsumerConnectionPoint(consumer, null);
2605             }
2606 
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) {
2614                         return connection;
2615                     }
2616                 }
2617             }
2618 
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) {
2624                         return connection;
2625                     }
2626                 }
2627             }
2628 
2629             return null;
2630         }
2631 
2632         /// <devdoc>
2633         /// If the WebPart is a provider on the given connection point, returns the corresponding connection.
2634         /// Else, returns null.
2635         /// </devdoc>
GetConnectionForProvider(WebPart provider, ProviderConnectionPoint connectionPoint)2636         internal WebPartConnection GetConnectionForProvider(WebPart provider, ProviderConnectionPoint connectionPoint) {
2637             ProviderConnectionPoint actualConnectionPoint = connectionPoint;
2638             if (connectionPoint == null) {
2639                 actualConnectionPoint = GetProviderConnectionPoint(provider, null);
2640             }
2641 
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) {
2649                         return connection;
2650                     }
2651                 }
2652             }
2653 
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) {
2659                         return connection;
2660                     }
2661                 }
2662             }
2663 
2664             return null;
2665         }
2666 
ImportReadTo(XmlReader reader, string elementToFind)2667         private static void ImportReadTo(XmlReader reader, string elementToFind) {
2668             while (reader.Name != elementToFind) {
2669                 if (!reader.Read()) {
2670                     throw new XmlException();
2671                 }
2672             }
2673         }
2674 
ImportReadTo(XmlReader reader, string elementToFindA, string elementToFindB)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();
2679                 }
2680             }
2681         }
2682 
ImportSkipTo(XmlReader reader, string elementToFind)2683         private static void ImportSkipTo(XmlReader reader, string elementToFind) {
2684             while (reader.Name != elementToFind) {
2685                 reader.Skip();
2686                 if (reader.EOF) {
2687                     throw new XmlException();
2688                 }
2689             }
2690         }
2691 
2692         /// <devdoc>
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.
2696         /// </devdoc>
ImportWebPart(XmlReader reader, out string errorMessage)2697         public virtual WebPart ImportWebPart(XmlReader reader, out string errorMessage) {
2698             Personalization.EnsureEnabled(/* ensureModifiable */ true);
2699 
2700             if (reader == null) {
2701                 throw new ArgumentNullException("reader");
2702             }
2703 
2704             bool permitOnly = false;
2705 
2706             if (UsePermitOnly) {
2707                 MinimalPermissionSet.PermitOnly();
2708                 permitOnly = true;
2709             }
2710             string importErrorMessage = string.Empty;
2711             // Extra try-catch block to prevent elevation of privilege attack via exception filter
2712             try {
2713                 try {
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);
2722                         return null;
2723                     }
2724                     if (!String.Equals(version, ExportPartNamespaceValue, StringComparison.OrdinalIgnoreCase)) {
2725                         errorMessage = SR.GetString(SR.WebPart_ImportErrorInvalidVersion);
2726                         return null;
2727                     }
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
2740                     Type partType;
2741                     WebPart part = null;
2742                     Control childControl = null;
2743 
2744                     try {
2745                         // If we are in shared scope, we are importing a shared WebPart
2746                         bool isShared = (Personalization.Scope == PersonalizationScope.Shared);
2747 
2748                         if (!String.IsNullOrEmpty(partTypeName)) {
2749 
2750                             if (UsePermitOnly) {
2751                                 CodeAccessPermission.RevertPermitOnly();
2752                                 permitOnly = false;
2753                                 MediumPermissionSet.PermitOnly();
2754                                 permitOnly = true;
2755                             }
2756 
2757                             partType = WebPartUtil.DeserializeType(partTypeName, true);
2758 
2759                             if (UsePermitOnly) {
2760                                 CodeAccessPermission.RevertPermitOnly();
2761                                 permitOnly = false;
2762                                 MinimalPermissionSet.PermitOnly();
2763                                 permitOnly = true;
2764                             }
2765 
2766                             // First check if the type is authorized
2767                             if (!IsAuthorized(partType, null, null, isShared)) {
2768                                 errorMessage = SR.GetString(SR.WebPartManager_ForbiddenType);
2769                                 return null;
2770                             }
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);
2776                                     return null;
2777                                 }
2778                                 // Create an instance of the object
2779                                 childControl = (Control)(Internals.CreateObjectFromType(partType));
2780                                 childControl.ID = CreateDynamicWebPartID(partType);
2781                                 part = CreateWebPart(childControl);
2782                             }
2783                             else {
2784                                 // Create an instance of the object
2785                                 part = (WebPart)(Internals.CreateObjectFromType(partType));
2786                             }
2787                         }
2788                         else {
2789                             // Instantiate a user control in a generic web part
2790 
2791                             // Check if the path is authorized
2792                             if (!IsAuthorized(typeof(UserControl), userControlTypeName, null, isShared)) {
2793                                 errorMessage = SR.GetString(SR.WebPartManager_ForbiddenType);
2794                                 return null;
2795                             }
2796 
2797                             if (UsePermitOnly) {
2798                                 CodeAccessPermission.RevertPermitOnly();
2799                                 permitOnly = false;
2800                             }
2801                             childControl = Page.LoadControl(userControlTypeName);
2802                             partType = childControl.GetType();
2803                             if (UsePermitOnly) {
2804                                 MinimalPermissionSet.PermitOnly();
2805                                 permitOnly = true;
2806                             }
2807                             childControl.ID = CreateDynamicWebPartID(partType);
2808                             part = CreateWebPart(childControl);
2809                         }
2810                     }
2811                     catch {
2812                         if (!String.IsNullOrEmpty(importErrorMessage)) {
2813                             errorMessage = importErrorMessage;
2814                         }
2815                         else {
2816                             errorMessage = SR.GetString(SR.WebPartManager_ErrorLoadingWebPartType);
2817                         }
2818                         return null;
2819                     }
2820 
2821                     // Set default error message for all subsequent errors
2822                     if (String.IsNullOrEmpty(importErrorMessage)) {
2823                         importErrorMessage = SR.GetString(SR.WebPart_DefaultImportErrorMessage);
2824                     }
2825                     // Get to the data
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();
2835                             permitOnly = false;
2836                         }
2837                         ImportIPersonalizable(reader, (childControl != null ? childControl : part));
2838                         if (UsePermitOnly) {
2839                             MinimalPermissionSet.PermitOnly();
2840                             permitOnly = true;
2841                         }
2842                     }
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);
2849 
2850                             // Copied from below.  We must also execute this code when parsing the ChildControl
2851                             // IPersonalizable and Personalizable properties.
2852                             while (reader.Name != ExportPropertyElement) {
2853                                 reader.Skip();
2854                                 if (reader.EOF) {
2855                                     errorMessage = null;
2856                                     return part;
2857                                 }
2858                             }
2859 
2860                             // ImportFromReader will set the right permission set when appropriate, reverting before we call
2861                             if (UsePermitOnly) {
2862                                 CodeAccessPermission.RevertPermitOnly();
2863                                 permitOnly = false;
2864                             }
2865                             ImportFromReader(personalizableProperties, childControl, reader);
2866                             if (UsePermitOnly) {
2867                                 MinimalPermissionSet.PermitOnly();
2868                                 permitOnly = true;
2869                             }
2870                         }
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();
2877                             permitOnly = false;
2878                         }
2879                         ImportIPersonalizable(reader, part);
2880                         if (UsePermitOnly) {
2881                             MinimalPermissionSet.PermitOnly();
2882                             permitOnly = true;
2883                         }
2884                         personalizableProperties = PersonalizableAttribute.GetPersonalizablePropertyEntries(part.GetType());
2885                     }
2886                     else {
2887                         // Get the collection of personalizable properties
2888                         personalizableProperties = PersonalizableAttribute.GetPersonalizablePropertyEntries(partType);
2889                     }
2890 
2891                     while (reader.Name != ExportPropertyElement) {
2892                         reader.Skip();
2893                         if (reader.EOF) {
2894                             errorMessage = null;
2895                             return part;
2896                         }
2897                     }
2898 
2899                     // ImportFromReader will set the right permission set when appropriate, reverting before we call
2900                     if (UsePermitOnly) {
2901                         CodeAccessPermission.RevertPermitOnly();
2902                         permitOnly = false;
2903                     }
2904                     ImportFromReader(personalizableProperties, part, reader);
2905                     if (UsePermitOnly) {
2906                         MinimalPermissionSet.PermitOnly();
2907                         permitOnly = true;
2908                     }
2909                     errorMessage = null;
2910                     // Return imported part
2911                     return part;
2912                 }
2913                 catch (XmlException) {
2914                     errorMessage = SR.GetString(SR.WebPartManager_ImportInvalidFormat);
2915                     return null;
2916                 }
2917                 catch (Exception e) {
2918                     if ((Context != null) && (Context.IsCustomErrorEnabled)) {
2919                         errorMessage = (importErrorMessage.Length != 0) ?
2920                             importErrorMessage :
2921                             SR.GetString(SR.WebPart_DefaultImportErrorMessage);
2922                     }
2923                     else {
2924                         errorMessage = e.Message;
2925                     }
2926                     return null;
2927                 }
2928                 finally {
2929                     if (permitOnly) {
2930                         // revert if you're not just exiting the stack frame anyway
2931                         CodeAccessPermission.RevertPermitOnly();
2932                     }
2933                 }
2934             }
2935             catch {
2936                 throw;
2937             }
2938         }
2939 
ImportIPersonalizable(XmlReader reader, Control control)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)
2947 
2948                 // Read to the next element that is either "property" or "ipersonalizable".
2949                 ImportReadTo(reader, ExportIPersonalizableElement, ExportPropertyElement);
2950 
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);
2958                 }
2959             }
2960         }
2961 
ImportFromReader(IDictionary personalizableProperties, Control target, XmlReader reader)2962         private void ImportFromReader(IDictionary personalizableProperties,
2963                                       Control target,
2964                                       XmlReader reader) {
2965 
2966             Debug.Assert(target != null);
2967 
2968             ImportReadTo(reader, ExportPropertyElement);
2969 
2970             bool permitOnly = false;
2971 
2972             if (UsePermitOnly) {
2973                 MinimalPermissionSet.PermitOnly();
2974                 permitOnly = true;
2975             }
2976 
2977             try {
2978                 try {
2979                     IDictionary properties;
2980                     if (personalizableProperties != null) {
2981                         properties = new HybridDictionary();
2982                     }
2983                     else {
2984                         properties = new PersonalizationDictionary();
2985                     }
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),
2994                             "true",
2995                             StringComparison.OrdinalIgnoreCase);
2996 
2997                         // Do not import Zone information or AuthorizationFilter or custom data
2998                         if (propertyName == AuthorizationFilterName ||
2999                              propertyName == ZoneIDName ||
3000                              propertyName == ZoneIndexName) {
3001 
3002                             reader.ReadElementString();
3003                             if (!reader.Read()) {
3004                                 throw new XmlException();
3005                             }
3006                         }
3007                         else {
3008                             string valString = reader.ReadElementString();
3009                             object val = null;
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));
3022                                     }
3023                                 }
3024                             }
3025 
3026                             Type type = null;
3027                             if (!String.IsNullOrEmpty(typeName)) {
3028                                 if (UsePermitOnly) {
3029                                     // Need medium trust to call BuildManager.GetType()
3030                                     CodeAccessPermission.RevertPermitOnly();
3031                                     permitOnly = false;
3032                                     MediumPermissionSet.PermitOnly();
3033                                     permitOnly = true;
3034                                 }
3035                                 type = GetExportType(typeName);
3036 
3037                                 if (UsePermitOnly) {
3038                                     CodeAccessPermission.RevertPermitOnly();
3039                                     permitOnly = false;
3040                                     MinimalPermissionSet.PermitOnly();
3041                                     permitOnly = true;
3042                                 }
3043                             }
3044 
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;
3049                                 if (attr != null) {
3050                                     if (UsePermitOnly) {
3051                                         // Need medium trust to call BuildManager.GetType()
3052                                         CodeAccessPermission.RevertPermitOnly();
3053                                         permitOnly = false;
3054                                         MediumPermissionSet.PermitOnly();
3055                                         permitOnly = true;
3056                                     }
3057 
3058                                     Type converterType = WebPartUtil.DeserializeType(attr.ConverterTypeName, false);
3059 
3060                                     if (UsePermitOnly) {
3061                                         CodeAccessPermission.RevertPermitOnly();
3062                                         permitOnly = false;
3063                                         MinimalPermissionSet.PermitOnly();
3064                                         permitOnly = true;
3065                                     }
3066 
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))) {
3071                                             if (!isNull) {
3072                                                 val = converter.ConvertFromInvariantString(valString);
3073                                             }
3074                                             valueComputed = true;
3075                                         }
3076                                     }
3077                                 }
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))) {
3083                                         if (!isNull) {
3084                                             val = converter.ConvertFromInvariantString(valString);
3085                                         }
3086                                         valueComputed = true;
3087                                         // Not importing anything else for security reasons
3088                                     }
3089                                 }
3090                             }
3091                             // finally, use the XML-specified type
3092                             if (!valueComputed && (type != null)) {
3093                                 // Look at the XML-declared type
3094                                 if (type == typeof(string)) {
3095                                     if (!isNull) {
3096                                         val = valString;
3097                                     }
3098                                     valueComputed = true;
3099                                 }
3100                                 else {
3101                                     TypeConverter typeConverter = TypeDescriptor.GetConverter(type);
3102                                     if (Util.CanConvertToFrom(typeConverter, typeof(string))) {
3103                                         if (!isNull) {
3104                                             val = typeConverter.ConvertFromInvariantString(valString);
3105                                         }
3106                                         valueComputed = true;
3107                                     }
3108                                 }
3109                             }
3110 
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;
3117                             }
3118 
3119                             // Now we should have a value (val)
3120                             if (valueComputed) {
3121                                 if (personalizableProperties != null) {
3122                                     properties.Add(propertyName, val);
3123                                 }
3124                                 else {
3125                                     // Determine scope:
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));
3130                                 }
3131                             }
3132                             else {
3133                                 throw new HttpException(SR.GetString(SR.WebPartManager_ImportInvalidData, propertyName));
3134                             }
3135                         }
3136                         while (reader.Name != ExportPropertyElement) {
3137                             if (reader.EOF ||
3138                                 (reader.Name == ExportGenericPartPropertiesElement) ||
3139                                 (reader.Name == ExportPropertiesElement) ||
3140                                 ((reader.Name == ExportIPersonalizableElement) && (reader.NodeType == XmlNodeType.EndElement))) {
3141                                 goto EndOfData;
3142                             }
3143                             reader.Skip();
3144                         }
3145                     }
3146                     EndOfData:
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);
3153                             }
3154                         }
3155                     }
3156                     else {
3157                         Debug.Assert(target is IPersonalizable);
3158                         ((IPersonalizable)target).Load((PersonalizationDictionary)properties);
3159                     }
3160                 }
3161                 finally {
3162                     if (permitOnly) {
3163                         // revert if you're not just exiting the stack frame anyway
3164                         CodeAccessPermission.RevertPermitOnly();
3165                     }
3166                 }
3167             }
3168             catch {
3169                 throw;
3170             }
3171         }
3172 
IsAuthorized(Type type, string path, string authorizationFilter, bool isShared)3173         public virtual bool IsAuthorized(Type type, string path, string authorizationFilter, bool isShared) {
3174             if (type == null) {
3175                 throw new ArgumentNullException("type");
3176             }
3177 
3178             if (type == typeof(UserControl)) {
3179                 if (String.IsNullOrEmpty(path)) {
3180                     throw new ArgumentException(SR.GetString(SR.WebPartManager_PathCannotBeEmpty));
3181                 }
3182             }
3183             else {
3184                 if (!String.IsNullOrEmpty(path)) {
3185                     throw new ArgumentException(SR.GetString(SR.WebPartManager_PathMustBeEmpty, path));
3186                 }
3187             }
3188 
3189             WebPartAuthorizationEventArgs auth = new WebPartAuthorizationEventArgs(type, path, authorizationFilter, isShared);
3190             OnAuthorizeWebPart(auth);
3191             return auth.IsAuthorized;
3192         }
3193 
IsAuthorized(WebPart webPart)3194         public bool IsAuthorized(WebPart webPart) {
3195             if (webPart == null) {
3196                 throw new ArgumentNullException("webPart");
3197             }
3198 
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.
3201 
3202             // Calculate authorizationFilter from property value and personalization data
3203             string authorizationFilter = webPart.AuthorizationFilter;
3204 
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;
3212                 }
3213             }
3214 
3215             GenericWebPart genericWebPart = webPart as GenericWebPart;
3216             if (genericWebPart != null) {
3217                 Type childType = null;
3218                 string childPath = null;
3219 
3220                 Control childControl = genericWebPart.ChildControl;
3221                 UserControl childUserControl = childControl as UserControl;
3222                 if (childUserControl != null) {
3223                     childType = typeof(UserControl);
3224                     childPath = childUserControl.AppRelativeVirtualPath;
3225                 }
3226                 else {
3227                     childType = childControl.GetType();
3228                 }
3229 
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);
3233             }
3234             else {
3235                 return IsAuthorized(webPart.GetType(), null, authorizationFilter, webPart.IsShared);
3236             }
3237         }
3238 
IsConsumerConnected(WebPart consumer, ConsumerConnectionPoint connectionPoint)3239         internal bool IsConsumerConnected(WebPart consumer, ConsumerConnectionPoint connectionPoint) {
3240             return (GetConnectionForConsumer(consumer, connectionPoint) != null);
3241         }
3242 
IsProviderConnected(WebPart provider, ProviderConnectionPoint connectionPoint)3243         internal bool IsProviderConnected(WebPart provider, ProviderConnectionPoint connectionPoint) {
3244             return (GetConnectionForProvider(provider, connectionPoint) != null);
3245         }
3246 
3247         /// <devdoc>
3248         /// Loads the control state for those properties that should persist across postbacks
3249         /// even when EnableViewState=false.
3250         /// </devdoc>
LoadControlState(object savedState)3251         protected internal override void LoadControlState(object savedState) {
3252             if (savedState == null) {
3253                 base.LoadControlState(null);
3254             }
3255             else {
3256                 object[] myState = (object[])savedState;
3257                 if (myState.Length != controlStateArrayLength) {
3258                     throw new ArgumentException(SR.GetString(SR.Invalid_ControlState));
3259                 }
3260 
3261                 base.LoadControlState(myState[baseIndex]);
3262 
3263                 //
3264 
3265                 if (myState[selectedWebPartIndex] != null) {
3266                     // All dynamic parts must be loaded before this point, in case a dynamic part is the
3267                     // SelectedWebPart.
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));
3274                     }
3275                     else {
3276                         SetSelectedWebPart(selectedWebPart);
3277                     }
3278                 }
3279                 if (myState[displayModeIndex] != null) {
3280                     string modeName = (string)myState[displayModeIndex];
3281 
3282                     WebPartDisplayMode restoredDisplayMode = SupportedDisplayModes[modeName];
3283                     if (!restoredDisplayMode.IsEnabled(this)) {
3284                         // Throw
3285                     }
3286 
3287                     if (restoredDisplayMode == null) {
3288                         _displayMode = BrowseDisplayMode;
3289                         OnDisplayModeChanged(new WebPartDisplayModeEventArgs(null));
3290                     }
3291                     else {
3292                         _displayMode = restoredDisplayMode;
3293                     }
3294                 }
3295             }
3296         }
3297 
LoadCustomPersonalizationState(PersonalizationDictionary state)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;
3302         }
3303 
LoadDynamicConnections(PersonalizationEntry entry)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];
3315 
3316                         // Add a new connection to the collection
3317                         WebPartConnection connection = new WebPartConnection();
3318                         connection.ID = ID;
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);
3325 
3326                         Type type = dynamicConnectionState[i + 5] as Type;
3327                         if (type != null) {
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);
3334                             }
3335                             else {
3336                                 throw new InvalidOperationException(SR.GetString(SR.WebPartTransformerAttribute_NotTransformer, type.Name));
3337                             }
3338                         }
3339 
3340                         DynamicConnections.Add(connection);
3341                     }
3342                 }
3343             }
3344         }
3345 
LoadDynamicWebPart(string id, string typeName, string path, string genericWebPartID, bool isShared)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);
3349             if (type == null) {
3350                 string errorMessage;
3351                 if (Context != null && Context.IsCustomErrorEnabled) {
3352                     errorMessage = SR.GetString(SR.WebPartManager_ErrorLoadingWebPartType);
3353                 }
3354                 else {
3355                     errorMessage = SR.GetString(SR.Invalid_type, typeName);
3356                 }
3357                 dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage);
3358             }
3359             else if (type.IsSubclassOf(typeof(WebPart))) {
3360                 string authorizationFilter = Personalization.GetAuthorizationFilter(id);
3361                 if (IsAuthorized(type, null, authorizationFilter, isShared)) {
3362                     try {
3363                         dynamicWebPart = (WebPart)Internals.CreateObjectFromType(type);
3364                         dynamicWebPart.ID = id;
3365                     }
3366                     catch {
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);
3372                         }
3373                         else {
3374                             errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstanceWithType, typeName);
3375                         }
3376                         dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage);
3377                     }
3378                 }
3379                 else {
3380                     dynamicWebPart = new UnauthorizedWebPart(id, typeName, path, genericWebPartID);
3381                 }
3382             }
3383             else if (type.IsSubclassOf(typeof(Control))) {
3384                 string authorizationFilter = Personalization.GetAuthorizationFilter(genericWebPartID);
3385                 if (IsAuthorized(type, path, authorizationFilter, isShared)) {
3386                     Control childControl = null;
3387                     try {
3388                         if (!String.IsNullOrEmpty(path)) {
3389                             Debug.Assert(type == typeof(UserControl));
3390                             childControl = Page.LoadControl(path);
3391                         }
3392                         else {
3393                             childControl = (Control)Internals.CreateObjectFromType(type);
3394                         }
3395                         childControl.ID = id;
3396 
3397                         dynamicWebPart = CreateWebPart(childControl);
3398                         dynamicWebPart.ID = genericWebPartID;
3399                     }
3400                     catch {
3401                         string errorMessage;
3402                         if (childControl == null && String.IsNullOrEmpty(path)) {
3403                             if (Context != null && Context.IsCustomErrorEnabled) {
3404                                 errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstance);
3405                             }
3406                             else {
3407                                 errorMessage = SR.GetString(SR.WebPartManager_CantCreateInstanceWithType, typeName);
3408                             }
3409                         }
3410                         else if (childControl == null) {
3411                             if (Context != null && Context.IsCustomErrorEnabled) {
3412                                 errorMessage = SR.GetString(SR.WebPartManager_InvalidPath);
3413                             }
3414                             else {
3415                                 errorMessage = SR.GetString(SR.WebPartManager_InvalidPathWithPath, path);
3416                             }
3417                         }
3418                         else {
3419                             errorMessage = SR.GetString(SR.WebPartManager_CantCreateGeneric);
3420                         }
3421                         dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage);
3422                     }
3423                 }
3424                 else {
3425                     dynamicWebPart = new UnauthorizedWebPart(id, typeName, path, genericWebPartID);
3426                 }
3427             }
3428             else {
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);
3434                 }
3435                 else {
3436                     errorMessage = SR.GetString(SR.WebPartManager_TypeMustDeriveFromControlWithType, typeName);
3437                 }
3438                 dynamicWebPart = CreateErrorWebPart(id, typeName, path, genericWebPartID, errorMessage);
3439             }
3440 
3441             Debug.Assert(dynamicWebPart != null);
3442             Internals.SetIsStatic(dynamicWebPart, false);
3443             Internals.SetIsShared(dynamicWebPart, isShared);
3444             Internals.AddWebPart(dynamicWebPart);
3445         }
3446 
LoadDynamicWebParts(PersonalizationEntry entry)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);
3453 
3454                     //
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];
3460 
3461                         LoadDynamicWebPart(id, typeName, path, genericWebPartID, isShared);
3462                     }
3463                 }
3464             }
3465         }
3466 
LoadDeletedConnectionState(PersonalizationEntry entry)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;
3474 
3475                         foreach (WebPartConnection connection in StaticConnections) {
3476                             if (String.Equals(connection.ID, idToDelete, StringComparison.OrdinalIgnoreCase)) {
3477                                 connectionToDelete = connection;
3478                                 break;
3479                             }
3480                         }
3481                         if (connectionToDelete == null) {
3482                             foreach (WebPartConnection connection in DynamicConnections) {
3483                                 if (String.Equals(connection.ID, idToDelete, StringComparison.OrdinalIgnoreCase)) {
3484                                     connectionToDelete = connection;
3485                                     break;
3486                                 }
3487                             }
3488                         }
3489 
3490                         if (connectionToDelete != null) {
3491                             // Only shared connections can be deleted
3492                             Debug.Assert(connectionToDelete.IsShared);
3493 
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);
3497 
3498                             Internals.DeleteConnection(connectionToDelete);
3499                         }
3500                         else {
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;
3504                         }
3505                     }
3506                 }
3507             }
3508         }
3509 
3510         /// <devdoc>
3511         /// Sets the ZoneID, ZoneIndex, and IsClosed properties on the WebParts.  The state
3512         /// was loaded from personalization.
3513         /// </devdoc>
LoadWebPartState(PersonalizationEntry entry)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];
3524 
3525                         WebPart part = (WebPart)FindControl(id);
3526                         if (part != null) {
3527                             Internals.SetZoneID(part, zoneID);
3528                             Internals.SetZoneIndex(part, zoneIndex);
3529                             //
3530 
3531                             Internals.SetIsClosed(part, isClosed);
3532                         }
3533                         else {
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;
3537                         }
3538                     }
3539                 }
3540             }
3541         }
3542 
3543         /// <devdoc>
3544         /// </devdoc>
MoveWebPart(WebPart webPart, WebPartZoneBase zone, int zoneIndex)3545         public virtual void MoveWebPart(WebPart webPart, WebPartZoneBase zone, int zoneIndex) {
3546             Personalization.EnsureEnabled(/* ensureModifiable */ true);
3547 
3548             if (webPart == null) {
3549                 throw new ArgumentNullException("webPart");
3550             }
3551             if (!Controls.Contains(webPart)) {
3552                 throw new ArgumentException(SR.GetString(SR.UnknownWebPart), "webPart");
3553             }
3554             if (zone == null) {
3555                 throw new ArgumentNullException("zone");
3556             }
3557             if (_webPartZones.Contains(zone) == false) {
3558                 throw new ArgumentException(SR.GetString(SR.WebPartManager_MustRegister), "zone");
3559             }
3560             if (zoneIndex < 0) {
3561                 throw new ArgumentOutOfRangeException("zoneIndex");
3562             }
3563             if (webPart.Zone == null || webPart.IsClosed) {
3564                 throw new ArgumentException(SR.GetString(SR.WebPartManager_MustBeInZone), "webPart");
3565             }
3566 
3567             // Return immediately if moving part to its current location
3568             if ((webPart.Zone == zone) && (webPart.ZoneIndex == zoneIndex)) {
3569                 return;
3570             }
3571 
3572             WebPartMovingEventArgs e = new WebPartMovingEventArgs(webPart, zone, zoneIndex);
3573             OnWebPartMoving(e);
3574             if (_allowEventCancellation && e.Cancel) {
3575                 return;
3576             }
3577 
3578             RemoveWebPartFromZone(webPart);
3579             AddWebPartToZone(webPart, zone, zoneIndex);
3580 
3581             // Raise event at very end of Move method
3582             OnWebPartMoved(new WebPartEventArgs(webPart));
3583 
3584 #if DEBUG
3585             CheckPartZoneIndexes(webPart.Zone);
3586             CheckPartZoneIndexes(zone);
3587 #endif
3588         }
3589 
OnAuthorizeWebPart(WebPartAuthorizationEventArgs e)3590         protected virtual void OnAuthorizeWebPart(WebPartAuthorizationEventArgs e) {
3591             WebPartAuthorizationEventHandler handler = (WebPartAuthorizationEventHandler)Events[AuthorizeWebPartEvent];
3592             if (handler != null) {
3593                 handler(this, e);
3594             }
3595         }
3596 
OnConnectionsActivated(EventArgs e)3597         protected virtual void OnConnectionsActivated(EventArgs e) {
3598             EventHandler handler = (EventHandler)Events[ConnectionsActivatedEvent];
3599             if (handler != null) {
3600                 handler(this, e);
3601             }
3602         }
3603 
OnConnectionsActivating(EventArgs e)3604         protected virtual void OnConnectionsActivating(EventArgs e) {
3605             EventHandler handler = (EventHandler)Events[ConnectionsActivatingEvent];
3606             if (handler != null) {
3607                 handler(this, e);
3608             }
3609         }
3610 
OnDisplayModeChanged(WebPartDisplayModeEventArgs e)3611         protected virtual void OnDisplayModeChanged(WebPartDisplayModeEventArgs e) {
3612             WebPartDisplayModeEventHandler handler = (WebPartDisplayModeEventHandler)Events[DisplayModeChangedEvent];
3613             if (handler != null) {
3614                 handler(this, e);
3615             }
3616         }
3617 
OnDisplayModeChanging(WebPartDisplayModeCancelEventArgs e)3618         protected virtual void OnDisplayModeChanging(WebPartDisplayModeCancelEventArgs e) {
3619             WebPartDisplayModeCancelEventHandler handler = (WebPartDisplayModeCancelEventHandler)Events[DisplayModeChangingEvent];
3620             if (handler != null) {
3621                 handler(this, e);
3622             }
3623         }
3624 
3625         /// <devdoc>
3626         /// </devdoc>
OnInit(EventArgs e)3627         protected internal override void OnInit(EventArgs e) {
3628             base.OnInit(e);
3629 
3630             if (!DesignMode) {
3631                 Page page = Page;
3632                 if (page != null) {
3633                     WebPartManager existingInstance = (WebPartManager)page.Items[typeof(WebPartManager)];
3634 
3635                     if (existingInstance != null) {
3636                         Debug.Assert(existingInstance != this);
3637                         throw new InvalidOperationException(SR.GetString(SR.WebPartManager_OnlyOneInstance));
3638                     }
3639 
3640                     page.Items[typeof(WebPartManager)] = this;
3641 
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);
3646 
3647                     Personalization.LoadInternal();
3648                 }
3649             }
3650         }
3651 
3652         /// <devdoc>
3653         /// </devdoc>
OnUnload(EventArgs e)3654         protected internal override void OnUnload(EventArgs e) {
3655             base.OnUnload(e);
3656 
3657             if (!DesignMode) {
3658                 Page page = Page;
3659 
3660                 Debug.Assert(page != null);
3661                 if (page != null) {
3662                     page.Items.Remove(typeof(WebPartManager));
3663                 }
3664             }
3665         }
3666 
OnPageInitComplete(object sender, EventArgs e)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"]);
3675 
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"]);
3682             }
3683 
3684             _pageInitComplete = true;
3685         }
3686 
OnPageLoadComplete(object sender, EventArgs e)3687         private void OnPageLoadComplete(object sender, EventArgs e) {
3688             // VSWhidbey 77708
3689             CloseOrphanedParts();
3690 
3691             _allowCreateDisplayTitles = true;
3692 
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);
3699         }
3700 
OnPageSaveStateComplete(object sender, EventArgs e)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);
3713             }
3714 
3715             Personalization.SaveInternal();
3716         }
3717 
OnPreRender(EventArgs e)3718         protected internal override void OnPreRender(EventArgs e) {
3719             base.OnPreRender(e);
3720 
3721             if (Page != null) {
3722                 Page.ClientScript.RegisterStartupScript(
3723                     this,
3724                     typeof(WebPartManager),
3725                     ExportSensitiveDataWarningDeclaration,
3726                     "var __wpmExportWarning='" + Util.QuoteJScriptString(ExportSensitiveDataWarning) + "';",
3727                     true);
3728 
3729                 Page.ClientScript.RegisterStartupScript(
3730                     this,
3731                     typeof(WebPartManager),
3732                     CloseProviderWarningDeclaration,
3733                     "var __wpmCloseProviderWarning='" + Util.QuoteJScriptString(CloseProviderWarning) + "';",
3734                     true);
3735 
3736                 Page.ClientScript.RegisterStartupScript(
3737                     this,
3738                     typeof(WebPartManager),
3739                     DeleteWarningDeclaration,
3740                     "var __wpmDeleteWarning='" + Util.QuoteJScriptString(DeleteWarning) + "';",
3741                     true);
3742 
3743                 _renderClientScript = CheckRenderClientScript();
3744                 if (_renderClientScript) {
3745                     //
3746 
3747                     Page.RegisterPostBackScript();
3748 
3749                     RegisterClientScript();
3750                 }
3751             }
3752         }
3753 
OnSelectedWebPartChanged(WebPartEventArgs e)3754         protected virtual void OnSelectedWebPartChanged(WebPartEventArgs e) {
3755             WebPartEventHandler handler = (WebPartEventHandler)Events[SelectedWebPartChangedEvent];
3756             if (handler != null) {
3757                 handler(this, e);
3758             }
3759         }
3760 
OnSelectedWebPartChanging(WebPartCancelEventArgs e)3761         protected virtual void OnSelectedWebPartChanging(WebPartCancelEventArgs e) {
3762             WebPartCancelEventHandler handler = (WebPartCancelEventHandler)Events[SelectedWebPartChangingEvent];
3763             if (handler != null) {
3764                 handler(this, e);
3765             }
3766         }
3767 
OnWebPartAdded(WebPartEventArgs e)3768         protected virtual void OnWebPartAdded(WebPartEventArgs e) {
3769             WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartAddedEvent];
3770             if (handler != null) {
3771                 handler(this, e);
3772             }
3773         }
3774 
OnWebPartAdding(WebPartAddingEventArgs e)3775         protected virtual void OnWebPartAdding(WebPartAddingEventArgs e) {
3776             WebPartAddingEventHandler handler = (WebPartAddingEventHandler)Events[WebPartAddingEvent];
3777             if (handler != null) {
3778                 handler(this, e);
3779             }
3780         }
3781 
OnWebPartClosed(WebPartEventArgs e)3782         protected virtual void OnWebPartClosed(WebPartEventArgs e) {
3783             WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartClosedEvent];
3784             if (handler != null) {
3785                 handler(this, e);
3786             }
3787         }
3788 
OnWebPartClosing(WebPartCancelEventArgs e)3789         protected virtual void OnWebPartClosing(WebPartCancelEventArgs e) {
3790             WebPartCancelEventHandler handler = (WebPartCancelEventHandler)Events[WebPartClosingEvent];
3791             if (handler != null) {
3792                 handler(this, e);
3793             }
3794 
3795         }
3796 
OnWebPartDeleted(WebPartEventArgs e)3797         protected virtual void OnWebPartDeleted(WebPartEventArgs e) {
3798             WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartDeletedEvent];
3799             if (handler != null) {
3800                 handler(this, e);
3801             }
3802         }
3803 
OnWebPartDeleting(WebPartCancelEventArgs e)3804         protected virtual void OnWebPartDeleting(WebPartCancelEventArgs e) {
3805             WebPartCancelEventHandler handler = (WebPartCancelEventHandler)Events[WebPartDeletingEvent];
3806             if (handler != null) {
3807                 handler(this, e);
3808             }
3809         }
3810 
OnWebPartMoved(WebPartEventArgs e)3811         protected virtual void OnWebPartMoved(WebPartEventArgs e) {
3812             WebPartEventHandler handler = (WebPartEventHandler)Events[WebPartMovedEvent];
3813             if (handler != null) {
3814                 handler(this, e);
3815             }
3816         }
3817 
OnWebPartMoving(WebPartMovingEventArgs e)3818         protected virtual void OnWebPartMoving(WebPartMovingEventArgs e) {
3819             WebPartMovingEventHandler handler = (WebPartMovingEventHandler)Events[WebPartMovingEvent];
3820             if (handler != null) {
3821                 handler(this, e);
3822             }
3823         }
3824 
OnWebPartsConnected(WebPartConnectionsEventArgs e)3825         protected virtual void OnWebPartsConnected(WebPartConnectionsEventArgs e) {
3826             WebPartConnectionsEventHandler handler = (WebPartConnectionsEventHandler)Events[WebPartsConnectedEvent];
3827             if (handler != null) {
3828                 handler(this, e);
3829             }
3830         }
3831 
OnWebPartsConnecting(WebPartConnectionsCancelEventArgs e)3832         protected virtual void OnWebPartsConnecting(WebPartConnectionsCancelEventArgs e) {
3833             WebPartConnectionsCancelEventHandler handler = (WebPartConnectionsCancelEventHandler)Events[WebPartsConnectingEvent];
3834             if (handler != null) {
3835                 handler(this, e);
3836             }
3837         }
3838 
OnWebPartsDisconnected(WebPartConnectionsEventArgs e)3839         protected virtual void OnWebPartsDisconnected(WebPartConnectionsEventArgs e) {
3840             WebPartConnectionsEventHandler handler = (WebPartConnectionsEventHandler)Events[WebPartsDisconnectedEvent];
3841             if (handler != null) {
3842                 handler(this, e);
3843             }
3844         }
3845 
OnWebPartsDisconnecting(WebPartConnectionsCancelEventArgs e)3846         protected virtual void OnWebPartsDisconnecting(WebPartConnectionsCancelEventArgs e) {
3847             WebPartConnectionsCancelEventHandler handler = (WebPartConnectionsCancelEventHandler)Events[WebPartsDisconnectingEvent];
3848             if (handler != null) {
3849                 handler(this, e);
3850             }
3851         }
3852 
RegisterClientScript()3853         protected virtual void RegisterClientScript() {
3854             Page.ClientScript.RegisterClientScriptResource(this, typeof(WebPartManager), "WebParts.js");
3855 
3856             bool allowPageDesign = DisplayMode.AllowPageDesign;
3857 
3858             string dragOverlayElementReference = "null";
3859             if (allowPageDesign) {
3860                 dragOverlayElementReference = "document.getElementById('" + ClientID + "___Drag')";
3861             }
3862 
3863             StringBuilder zoneCode = new StringBuilder(1024);
3864             foreach (WebPartZoneBase zone in _webPartZones) {
3865                 string isVertical = (zone.LayoutOrientation == Orientation.Vertical) ? "true" : "false";
3866 
3867                 string allowLayoutChange = "false";
3868                 string dragHighlightColor = "black";
3869                 if (allowPageDesign && zone.AllowLayoutChange) {
3870                     allowLayoutChange = "true";
3871                     dragHighlightColor = ColorTranslator.ToHtml(zone.DragHighlightColor);
3872                 }
3873 
3874                 zoneCode.AppendFormat(CultureInfo.InvariantCulture, ZoneScript, zone.ClientID, zone.UniqueID, isVertical,
3875                                       allowLayoutChange, dragHighlightColor);
3876 
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) {
3884                             allowMove = "true";
3885                         }
3886                     }
3887                     zoneCode.AppendFormat(ZonePartScript, webPart.WholePartID, titleBarElementReference, allowMove);
3888                 }
3889 
3890                 zoneCode.Append(ZoneEndScript);
3891             }
3892 
3893             string startupScript = String.Format(CultureInfo.InvariantCulture,
3894                                                  StartupScript,
3895                                                  dragOverlayElementReference,
3896                                                  (Personalization.Scope == PersonalizationScope.Shared ? "true" : "false"),
3897                                                  zoneCode.ToString());
3898             Page.ClientScript.RegisterStartupScript(this, typeof(WebPartManager), String.Empty, startupScript, false);
3899 
3900             IScriptManager scriptManager = Page.ScriptManager;
3901             if ((scriptManager != null) && scriptManager.SupportsPartialRendering) {
3902                 scriptManager.RegisterDispose(this, "WebPartManager_Dispose();");
3903             }
3904         }
3905 
RegisterZone(WebZone zone)3906         internal void RegisterZone(WebZone zone) {
3907             Debug.Assert(zone != null);
3908 
3909             if (_pageInitComplete) {
3910                 throw new InvalidOperationException(SR.GetString(SR.WebPartManager_RegisterTooLate));
3911             }
3912 
3913             string zoneID = zone.ID;
3914             if (String.IsNullOrEmpty(zoneID)) {
3915                 throw new ArgumentException(SR.GetString(SR.WebPartManager_NoZoneID), "zone");
3916             }
3917             if (_zoneIDs.Contains(zoneID)) {
3918                 throw new ArgumentException(SR.GetString(SR.WebPartManager_DuplicateZoneID, zoneID));
3919             }
3920             _zoneIDs.Add(zoneID, zone);
3921 
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");
3926                 }
3927 
3928                 _webPartZones.Add(webPartZone);
3929 
3930                 WebPartCollection initialWebParts = webPartZone.GetInitialWebParts();
3931                 ((WebPartManagerControlCollection)Controls).AddWebPartsFromZone(webPartZone, initialWebParts);
3932             }
3933             else {
3934                 Debug.Assert(zone is ToolZone);
3935                 ToolZone toolZone = (ToolZone)zone;
3936 
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);
3942                     }
3943                 }
3944             }
3945         }
3946 
3947         /// <devdoc>
3948         /// Deletes the part from the dictionary mapping zones to parts.
3949         /// </devdoc>
RemoveWebPartFromDictionary(WebPart webPart)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);
3957                     }
3958                 }
3959             }
3960         }
3961 
3962         // Called by WebPartManagerInternals
RemoveWebPart(WebPart webPart)3963         internal void RemoveWebPart(WebPart webPart) {
3964             ((WebPartManagerControlCollection)Controls).RemoveWebPart(webPart);
3965         }
3966 
3967         /// <devdoc>
3968         /// Removes a web part from its zone, and renumbers all the remaining parts sequentially.
3969         /// </devdoc>
RemoveWebPartFromZone(WebPart webPart)3970         private void RemoveWebPartFromZone(WebPart webPart) {
3971             Debug.Assert(!webPart.IsClosed);
3972 
3973             WebPartZoneBase zone = webPart.Zone;
3974             Internals.SetIsClosed(webPart, true);
3975             _hasDataChanged = true;
3976 
3977             RemoveWebPartFromDictionary(webPart);
3978 
3979             //
3980 
3981             if (zone != null) {
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);
3986                 }
3987             }
3988         }
3989 
Render(HtmlTextWriter writer)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);
3994             }
3995         }
3996 
3997         /// <devdoc>
3998         /// Saves the control state for those properties that should persist across postbacks
3999         /// even when EnableViewState=false.
4000         /// </devdoc>
SaveControlState()4001         protected internal override object SaveControlState() {
4002             object[] myState = new object[controlStateArrayLength];
4003 
4004             myState[baseIndex] = base.SaveControlState();
4005             if (SelectedWebPart != null) {
4006                 myState[selectedWebPartIndex] = SelectedWebPart.ID;
4007             }
4008             if (_displayMode != BrowseDisplayMode) {
4009                 myState[displayModeIndex] = _displayMode.Name;
4010             }
4011 
4012             for (int i=0; i < controlStateArrayLength; i++) {
4013                 if (myState[i] != null) {
4014                     return myState;
4015                 }
4016             }
4017 
4018             // More performant to return null than an array of null values
4019             return null;
4020         }
4021 
SaveCustomPersonalizationState(PersonalizationDictionary state)4022         protected virtual void SaveCustomPersonalizationState(PersonalizationDictionary state) {
4023             PersonalizationScope scope = Personalization.Scope;
4024 
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;
4034                 }
4035                 if (scope == PersonalizationScope.Shared) {
4036                     state["WebPartStateShared"] =
4037                         new PersonalizationEntry(webPartState, PersonalizationScope.Shared);
4038                 }
4039                 else {
4040                     state["WebPartStateUser"] =
4041                         new PersonalizationEntry(webPartState, PersonalizationScope.User);
4042                 }
4043             }
4044 
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);
4052                 }
4053             }
4054 
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];
4061 
4062                     string id;
4063                     string typeName;
4064                     string path = null;
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;
4072                     }
4073                     else {
4074                         GenericWebPart genericWebPart = webPart as GenericWebPart;
4075                         if (genericWebPart != null) {
4076                             Control childControl = genericWebPart.ChildControl;
4077                             UserControl userControl = childControl as UserControl;
4078 
4079                             id = childControl.ID;
4080                             if (userControl != null) {
4081                                 typeName = WebPartUtil.SerializeType(typeof(UserControl));
4082                                 path = userControl.AppRelativeVirtualPath;
4083                             }
4084                             else {
4085                                 typeName = WebPartUtil.SerializeType(childControl.GetType());
4086                             }
4087                             genericWebPartID = genericWebPart.ID;
4088                         }
4089                         else {
4090                             id = webPart.ID;
4091                             typeName = WebPartUtil.SerializeType(webPart.GetType());
4092                         }
4093                     }
4094 
4095                     dynamicWebPartState[4*i] = id;
4096                     dynamicWebPartState[4*i + 1] = typeName;
4097                     if (!String.IsNullOrEmpty(path)) {
4098                         dynamicWebPartState[4*i + 2] = path;
4099                     }
4100                     if (!String.IsNullOrEmpty(genericWebPartID)) {
4101                         dynamicWebPartState[4*i + 3] = genericWebPartID;
4102                     }
4103                 }
4104                 if (scope == PersonalizationScope.Shared) {
4105                     state["DynamicWebPartsShared"] =
4106                         new PersonalizationEntry(dynamicWebPartState, PersonalizationScope.Shared);
4107                 }
4108                 else {
4109                     state["DynamicWebPartsUser"] =
4110                         new PersonalizationEntry(dynamicWebPartState, PersonalizationScope.User);
4111                 }
4112             }
4113 
4114             // Save deleted connections
4115             //
4116 
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);
4123                 }
4124             }
4125             foreach (WebPartConnection connection in DynamicConnections) {
4126                 if (Internals.ConnectionDeleted(connection)) {
4127                     deletedConnections.Add(connection);
4128                 }
4129             }
4130 
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;
4142                 }
4143                 if (scope == PersonalizationScope.Shared) {
4144                     state["DeletedConnectionsShared"] =
4145                         new PersonalizationEntry(deletedConnectionsState, PersonalizationScope.Shared);
4146                 }
4147                 else {
4148                     state["DeletedConnectionsUser"] =
4149                         new PersonalizationEntry(deletedConnectionsState, PersonalizationScope.User);
4150                 }
4151             }
4152 
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);
4159                 }
4160             }
4161 
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;
4169 
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));
4173 
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);
4182                     }
4183                 }
4184 
4185                 if (scope == PersonalizationScope.Shared) {
4186                     state["DynamicConnectionsShared"] =
4187                         new PersonalizationEntry(dynamicConnectionState, PersonalizationScope.Shared);
4188                 }
4189                 else {
4190                     state["DynamicConnectionsUser"] =
4191                         new PersonalizationEntry(dynamicConnectionState, PersonalizationScope.User);
4192                 }
4193             }
4194         }
4195 
4196         // Can be called by a derived WebPartManager to mark itself as dirty
SetPersonalizationDirty()4197         protected void SetPersonalizationDirty() {
4198             Personalization.SetDirty();
4199         }
4200 
4201         // Returns true if the WebPart should currently be rendered in the Zone.  Determines
4202         // which WebParts are returned by GetWebPartsForZone.
ShouldRenderWebPartInZone(WebPart part, WebPartZoneBase zone)4203         private bool ShouldRenderWebPartInZone(WebPart part, WebPartZoneBase zone) {
4204             Debug.Assert(part.Zone == zone);
4205 
4206             // Never render UnauthorizedWebParts
4207             if (part is UnauthorizedWebPart) {
4208                 return false;
4209             }
4210 
4211             return true;
4212         }
4213 
SetSelectedWebPart(WebPart webPart)4214         protected void SetSelectedWebPart(WebPart webPart) {
4215             _selectedWebPart = webPart;
4216         }
4217 
4218         // PropertyInfo will be null for an IPersonalizable property, since there is no associated PropertyInfo
ShouldExportProperty(PropertyInfo propertyInfo, Type propertyValueType, object propertyValue, out string exportString)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;
4224                 return true;
4225             }
4226             else {
4227                 TypeConverter converter = null;
4228 
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;
4233                     if (attr != null) {
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;
4243                             }
4244                         }
4245                     }
4246                 }
4247 
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;
4253                     }
4254                 }
4255 
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);
4260                         return true;
4261                     }
4262                     else {
4263                         // Special-case null value
4264                         exportString = null;
4265                         return true;
4266                     }
4267                 }
4268                 else {
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)
4276                         return true;
4277                     }
4278                     else {
4279                         return false;
4280                     }
4281                 }
4282             }
4283         }
4284 
4285         /// <devdoc>
4286         /// Returns true if the connection should be removed from the dynamic connection
4287         /// collection when deleted.
4288         /// </devdoc>
ShouldRemoveConnection(WebPartConnection connection)4289         private bool ShouldRemoveConnection(WebPartConnection connection) {
4290             Debug.Assert(Personalization.IsModifiable);
4291 
4292             if (connection.IsShared && (Personalization.Scope == PersonalizationScope.User)) {
4293                 // Can't remove shared connection in user mode
4294                 return false;
4295             }
4296             else {
4297                 return true;
4298             }
4299         }
4300 
4301         /// <internalonly />
TrackViewState()4302         protected override void TrackViewState() {
4303             Personalization.ApplyPersonalizationState();
4304             base.TrackViewState();
4305         }
4306 
4307         // Throw if the type cannot be loaded by BuildManager
4308         // For instance, we cannot load a type defined in the Page class
VerifyType(Control control)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) {
4313                 return;
4314             }
4315 
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));
4322             }
4323         }
4324 
4325         #region Implementation of IPersonalizable
4326         /// <internalonly/>
4327         bool IPersonalizable.IsDirty {
4328             get {
4329                 return IsCustomPersonalizationStateDirty;
4330             }
4331         }
4332 
4333         /// <internalonly/>
IPersonalizable.Load(PersonalizationDictionary state)4334         void IPersonalizable.Load(PersonalizationDictionary state) {
4335             LoadCustomPersonalizationState(state);
4336         }
4337 
4338         /// <internalonly/>
IPersonalizable.Save(PersonalizationDictionary state)4339         void IPersonalizable.Save(PersonalizationDictionary state) {
4340             SaveCustomPersonalizationState(state);
4341         }
4342         #endregion
4343 
4344         private sealed class WebPartManagerControlCollection : ControlCollection {
4345 
4346             private WebPartManager _manager;
4347 
WebPartManagerControlCollection(WebPartManager owner)4348             public WebPartManagerControlCollection(WebPartManager owner) : base(owner) {
4349                 _manager = owner;
4350                 SetCollectionReadOnly(SR.WebPartManager_CannotModify);
4351             }
4352 
AddWebPart(WebPart webPart)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
4356                 try {
4357                     try {
4358                         AddWebPartHelper(webPart);
4359                     }
4360                     finally {
4361                         SetCollectionReadOnly(originalError);
4362                     }
4363                 }
4364                 catch {
4365                     throw;
4366                 }
4367             }
4368 
AddWebPartHelper(WebPart webPart)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));
4373                 }
4374                 if (_manager._partAndChildControlIDs.Contains(partID)) {
4375                    throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DuplicateWebPartID, partID));
4376                 }
4377 
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);
4381 
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;
4386 
4387                     if (String.IsNullOrEmpty(childControlID)) {
4388                         throw new InvalidOperationException(SR.GetString(SR.WebPartManager_NoChildControlID));
4389                     }
4390 
4391                     if (_manager._partAndChildControlIDs.Contains(childControlID)) {
4392                         throw new InvalidOperationException(SR.GetString(SR.WebPartManager_DuplicateWebPartID, childControlID));
4393                     }
4394 
4395                     _manager._partAndChildControlIDs.Add(childControlID, null);
4396                 }
4397 
4398                 _manager.Internals.SetIsStandalone(webPart, false);
4399                 webPart.SetWebPartManager(_manager);
4400                 Add(webPart);
4401 
4402                 // Invalidate the part dictionary if it has already been created
4403                 _manager._partsForZone = null;
4404             }
4405 
AddWebPartsFromZone(WebPartZoneBase zone, WebPartCollection webParts)4406             internal void AddWebPartsFromZone(WebPartZoneBase zone, WebPartCollection webParts) {
4407                 if ((webParts != null) && (webParts.Count != 0)) {
4408                     string originalError = SetCollectionReadOnly(null);
4409 
4410                     // Extra try-catch block to prevent elevation of privilege attack via exception filter
4411                     try {
4412                         try {
4413                             string zoneID = zone.ID;
4414                             int index = 0;
4415 
4416                             foreach (WebPart webPart in webParts) {
4417                                 // Need to set IsShared before calling IsAuthorized
4418                                 _manager.Internals.SetIsShared(webPart, true);
4419 
4420                                 WebPart webPartOrProxy = webPart;
4421                                 if (!_manager.IsAuthorized(webPart)) {
4422                                     webPartOrProxy = new UnauthorizedWebPart(webPart);
4423                                 }
4424 
4425                                 _manager.Internals.SetIsStatic(webPartOrProxy, true);
4426                                 _manager.Internals.SetIsShared(webPartOrProxy, true);
4427                                 _manager.Internals.SetZoneID(webPartOrProxy, zoneID);
4428                                 _manager.Internals.SetZoneIndex(webPartOrProxy, index);
4429 
4430                                 AddWebPartHelper(webPartOrProxy);
4431                                 index++;
4432                             }
4433                         }
4434                         finally {
4435                             SetCollectionReadOnly(originalError);
4436                         }
4437                     } catch {
4438                         throw;
4439                     }
4440                 }
4441             }
4442 
RemoveWebPart(WebPart webPart)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
4446                 try {
4447                     try {
4448                         _manager._partAndChildControlIDs.Remove(webPart.ID);
4449 
4450                         // Remove child control ID (VSWhidbey 339482)
4451                         GenericWebPart genericWebPart = webPart as GenericWebPart;
4452                         if (genericWebPart != null) {
4453                             _manager._partAndChildControlIDs.Remove(genericWebPart.ChildControl.ID);
4454                         }
4455 
4456                         Remove(webPart);
4457                         _manager._hasDataChanged = true;
4458                         webPart.SetWebPartManager(null);
4459                         _manager.Internals.SetIsStandalone(webPart, true);
4460 
4461                         // Invalidate the part dictionary if it has already been created
4462                         _manager._partsForZone = null;
4463                     }
4464                     finally {
4465                         SetCollectionReadOnly(originalError);
4466                     }
4467                 }
4468                 catch {
4469                     throw;
4470                 }
4471             }
4472         }
4473 
4474         private sealed class BrowseWebPartDisplayMode : WebPartDisplayMode {
4475 
BrowseWebPartDisplayMode()4476             public BrowseWebPartDisplayMode() : base("Browse") {
4477             }
4478         }
4479 
4480         private sealed class CatalogWebPartDisplayMode : WebPartDisplayMode {
4481 
CatalogWebPartDisplayMode()4482             public CatalogWebPartDisplayMode() : base("Catalog") {
4483             }
4484 
4485             public override bool AllowPageDesign {
4486                 get {
4487                     return true;
4488                 }
4489             }
4490 
4491             public override bool AssociatedWithToolZone {
4492                 get {
4493                     return true;
4494                 }
4495             }
4496 
4497             public override bool RequiresPersonalization {
4498                 get {
4499                     return true;
4500                 }
4501             }
4502 
4503             public override bool ShowHiddenWebParts {
4504                 get {
4505                     return true;
4506                 }
4507             }
4508         }
4509 
4510         private sealed class ConnectionPointKey {
4511             // DevDiv Bugs 38677
4512             // used as the Cache key for Connection Points, using Type and Culture
4513             private Type _type;
4514             private CultureInfo _culture;
4515             private CultureInfo _uiCulture;
4516 
ConnectionPointKey(Type type, CultureInfo culture, CultureInfo uiCulture)4517             public ConnectionPointKey(Type type, CultureInfo culture, CultureInfo uiCulture) {
4518                  Debug.Assert(type != null && culture != null && uiCulture != null);
4519 
4520                  _type = type;
4521                  _culture = culture;
4522                  _uiCulture = uiCulture;
4523             }
4524 
Equals(object obj)4525             public override bool Equals(object obj) {
4526                  if (obj == this) {
4527                       return true;
4528                  }
4529 
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));
4535             }
4536 
4537             [SuppressMessage("Microsoft.Usage", "CA2303:FlagTypeGetHashCode", Justification = "The types are Sytem.Web.UI.Control derived classes and not com interop types.")]
GetHashCode()4538             public override int GetHashCode()
4539             {
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();
4545             }
4546         }
4547 
4548         private sealed class ConnectWebPartDisplayMode : WebPartDisplayMode {
4549 
ConnectWebPartDisplayMode()4550             public ConnectWebPartDisplayMode() : base("Connect") {
4551             }
4552 
4553             public override bool AllowPageDesign {
4554                 get {
4555                     return true;
4556                 }
4557             }
4558 
4559             public override bool AssociatedWithToolZone {
4560                 get {
4561                     return true;
4562                 }
4563             }
4564 
4565             public override bool RequiresPersonalization {
4566                 get {
4567                     return true;
4568                 }
4569             }
4570 
4571             public override bool ShowHiddenWebParts {
4572                 get {
4573                     return true;
4574                 }
4575             }
4576         }
4577 
4578         private sealed class DesignWebPartDisplayMode : WebPartDisplayMode {
4579 
DesignWebPartDisplayMode()4580             public DesignWebPartDisplayMode() : base("Design") {
4581             }
4582 
4583             public override bool AllowPageDesign {
4584                 get {
4585                     return true;
4586                 }
4587             }
4588 
4589             public override bool RequiresPersonalization {
4590                 get {
4591                     return true;
4592                 }
4593             }
4594 
4595             public override bool ShowHiddenWebParts {
4596                 get {
4597                     return true;
4598                 }
4599             }
4600         }
4601 
4602         private sealed class EditWebPartDisplayMode : WebPartDisplayMode {
4603 
EditWebPartDisplayMode()4604             public EditWebPartDisplayMode() : base("Edit") {
4605             }
4606 
4607             public override bool AllowPageDesign {
4608                 get {
4609                     return true;
4610                 }
4611             }
4612 
4613             public override bool AssociatedWithToolZone {
4614                 get {
4615                     return true;
4616                 }
4617             }
4618 
4619             public override bool RequiresPersonalization {
4620                 get {
4621                     return true;
4622                 }
4623             }
4624 
4625             public override bool ShowHiddenWebParts {
4626                 get {
4627                     return true;
4628                 }
4629             }
4630         }
4631     }
4632 }
4633