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