1 //------------------------------------------------------------------------------ 2 // <copyright file="Menu.cs" company="Microsoft"> 3 // Copyright (c) Microsoft Corporation. All rights reserved. 4 // </copyright> 5 //------------------------------------------------------------------------------ 6 7 namespace System.Web.UI.WebControls { 8 using System.Collections; 9 using System.Collections.Generic; 10 using System.Collections.ObjectModel; 11 using System.ComponentModel; 12 using System.Drawing.Design; 13 using System.Globalization; 14 using System.IO; 15 using System.Reflection; 16 using System.Security.Permissions; 17 using System.Text; 18 using System.Web.UI.WebControls.Adapters; 19 using System.Web.Util; 20 21 /// <devdoc> 22 /// Provides a cascading pop-out hierarchical menu control 23 /// </devdoc> 24 [ControlValueProperty("SelectedValue")] 25 [DefaultEvent("MenuItemClick")] 26 [Designer("System.Web.UI.Design.WebControls.MenuDesigner, " + AssemblyRef.SystemDesign)] 27 [SupportsEventValidation] 28 public partial class Menu : HierarchicalDataBoundControl, IPostBackEventHandler, INamingContainer { 29 30 internal const int ScrollUpImageIndex = 0; 31 internal const int ScrollDownImageIndex = 1; 32 internal const int PopOutImageIndex = 2; 33 34 internal const int ImageUrlsCount = 3; 35 36 private const string _getDesignTimeStaticHtml = "GetDesignTimeStaticHtml"; 37 private const string _getDesignTimeDynamicHtml = "GetDesignTimeDynamicHtml"; 38 39 // static readonly instead of const to be able to change it in the future without breaking existing client code 40 public static readonly string MenuItemClickCommandName = "Click"; 41 42 private static readonly object _menuItemClickedEvent = new object(); 43 private static readonly object _menuItemDataBoundEvent = new object(); 44 45 private MenuRenderingMode _renderingMode = MenuRenderingMode.Default; 46 47 private string[] _imageUrls; 48 49 private SubMenuStyle _staticMenuStyle; 50 private SubMenuStyle _dynamicMenuStyle; 51 52 private MenuItemStyle _staticItemStyle; 53 private MenuItemStyle _staticSelectedStyle; 54 private Style _staticHoverStyle; 55 private HyperLinkStyle _staticHoverHyperLinkStyle; 56 57 private MenuItemStyle _dynamicItemStyle; 58 private MenuItemStyle _dynamicSelectedStyle; 59 private Style _dynamicHoverStyle; 60 private HyperLinkStyle _dynamicHoverHyperLinkStyle; 61 62 private Style _rootMenuItemStyle; 63 64 private SubMenuStyleCollection _levelStyles; 65 private MenuItemStyleCollection _levelMenuItemStyles; 66 private MenuItemStyleCollection _levelSelectedStyles; 67 68 // Cached styles. In the current implementation, the styles are the same for all items 69 // and submenus at a given depth. 70 private List<MenuItemStyle> _cachedMenuItemStyles; 71 private List<SubMenuStyle> _cachedSubMenuStyles; 72 private List<string> _cachedMenuItemClassNames; 73 private List<string> _cachedMenuItemHyperLinkClassNames; 74 private List<string> _cachedSubMenuClassNames; 75 private Collection<int> _cachedLevelsContainingCssClass; 76 77 private MenuItem _rootItem; 78 private MenuItem _selectedItem; 79 80 private MenuItemBindingCollection _bindings; 81 82 private string _cachedScrollUpImageUrl; 83 private string _cachedScrollDownImageUrl; 84 private string _cachedPopOutImageUrl; 85 86 private ITemplate _dynamicTemplate; 87 private ITemplate _staticTemplate; 88 89 private int _maximumDepth; 90 private int _nodeIndex; 91 92 private string _currentSiteMapNodeUrl; 93 private bool _dataBound; 94 private bool _subControlsDataBound; 95 private bool _accessKeyRendered; 96 97 private PopOutPanel _panel; 98 private Style _panelStyle; 99 100 private bool _isNotIE; 101 102 private Type _designTimeTextWriterType; 103 104 private MenuRenderer _renderer; 105 106 /// <devdoc> 107 /// Creates a new instance of a Menu. 108 /// </devdoc> Menu()109 public Menu() { 110 _nodeIndex = 0; 111 _maximumDepth = 0; 112 113 IncludeStyleBlock = true; 114 } 115 116 internal bool AccessKeyRendered { 117 get { 118 return _accessKeyRendered; 119 } 120 set { 121 _accessKeyRendered = value; 122 } 123 } 124 125 private Collection<int> CachedLevelsContainingCssClass { 126 get { 127 if (_cachedLevelsContainingCssClass == null) { 128 _cachedLevelsContainingCssClass = new Collection<int>(); 129 } 130 return _cachedLevelsContainingCssClass; 131 } 132 } 133 134 private List<string> CachedMenuItemClassNames { 135 get { 136 if (_cachedMenuItemClassNames == null) { 137 _cachedMenuItemClassNames = new List<string>(); 138 } 139 return _cachedMenuItemClassNames; 140 } 141 } 142 143 private List<string> CachedMenuItemHyperLinkClassNames { 144 get { 145 if (_cachedMenuItemHyperLinkClassNames == null) { 146 _cachedMenuItemHyperLinkClassNames = new List<string>(); 147 } 148 return _cachedMenuItemHyperLinkClassNames; 149 } 150 } 151 152 private List<MenuItemStyle> CachedMenuItemStyles { 153 get { 154 if (_cachedMenuItemStyles == null) { 155 _cachedMenuItemStyles = new List<MenuItemStyle>(); 156 } 157 return _cachedMenuItemStyles; 158 } 159 } 160 161 private List<string> CachedSubMenuClassNames { 162 get { 163 if (_cachedSubMenuClassNames == null) { 164 _cachedSubMenuClassNames = new List<string>(); 165 } 166 return _cachedSubMenuClassNames; 167 } 168 } 169 170 private List<SubMenuStyle> CachedSubMenuStyles { 171 get { 172 if (_cachedSubMenuStyles == null) { 173 _cachedSubMenuStyles = new List<SubMenuStyle>(); 174 } 175 return _cachedSubMenuStyles; 176 } 177 } 178 179 180 /// <devdoc> 181 /// Gets the hidden field ID for the expand state of this Menu 182 /// </devdoc> 183 internal string ClientDataObjectID { 184 get { 185 // 186 return ClientID + "_Data"; 187 } 188 } 189 190 public override ControlCollection Controls { 191 get { 192 EnsureChildControls(); 193 return base.Controls; 194 } 195 } 196 197 [ 198 DefaultValue(null), 199 Editor("System.Web.UI.Design.WebControls.MenuBindingsEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)), 200 MergableProperty(false), 201 PersistenceMode(PersistenceMode.InnerProperty), 202 WebCategory("Data"), 203 WebSysDescription(SR.Menu_Bindings) 204 ] 205 public MenuItemBindingCollection DataBindings { 206 get { 207 if (_bindings == null) { 208 _bindings = new MenuItemBindingCollection(this); 209 if (IsTrackingViewState) { 210 ((IStateManager)_bindings).TrackViewState(); 211 } 212 } 213 return _bindings; 214 } 215 } 216 217 218 [WebCategory("Behavior")] 219 [DefaultValue(500)] 220 [WebSysDescription(SR.Menu_DisappearAfter)] 221 [Themeable(false)] 222 public int DisappearAfter { 223 get { 224 object o = ViewState["DisappearAfter"]; 225 if (o == null) { 226 return 500; 227 } 228 return (int)o; 229 } 230 set { 231 if (value < -1) { 232 throw new ArgumentOutOfRangeException("value"); 233 } 234 ViewState["DisappearAfter"] = value; 235 } 236 } 237 238 239 [DefaultValue("")] 240 [Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))] 241 [Themeable(true)] 242 [UrlProperty()] 243 [WebCategory("Appearance")] 244 [WebSysDescription(SR.Menu_DynamicBottomSeparatorImageUrl)] 245 public string DynamicBottomSeparatorImageUrl { 246 get { 247 object s = ViewState["DynamicBottomSeparatorImageUrl"]; 248 if (s == null) { 249 return String.Empty; 250 } 251 return (string)s; 252 } 253 set { 254 ViewState["DynamicBottomSeparatorImageUrl"] = value; 255 } 256 } 257 258 259 [ 260 DefaultValue(true), 261 WebCategory("Appearance"), 262 WebSysDescription(SR.Menu_DynamicDisplayPopOutImage) 263 ] 264 public bool DynamicEnableDefaultPopOutImage { 265 get { 266 object o = ViewState["DynamicEnableDefaultPopOutImage"]; 267 if (o == null) { 268 return true; 269 } 270 return (bool)o; 271 } 272 set { 273 ViewState["DynamicEnableDefaultPopOutImage"] = value; 274 } 275 } 276 277 278 [ 279 DefaultValue(0), 280 WebCategory("Appearance"), 281 WebSysDescription(SR.Menu_DynamicHorizontalOffset) 282 ] 283 public int DynamicHorizontalOffset { 284 get { 285 object o = ViewState["DynamicHorizontalOffset"]; 286 if (o == null) { 287 return 0; 288 } 289 return (int)o; 290 } 291 set { 292 ViewState["DynamicHorizontalOffset"] = value; 293 } 294 } 295 296 297 [ 298 DefaultValue(null), 299 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 300 NotifyParentProperty(true), 301 PersistenceMode(PersistenceMode.InnerProperty), 302 WebCategory("Styles"), 303 WebSysDescription(SR.Menu_DynamicHoverStyle) 304 ] 305 public Style DynamicHoverStyle { 306 get { 307 if (_dynamicHoverStyle == null) { 308 _dynamicHoverStyle = new Style(); 309 if (IsTrackingViewState) { 310 ((IStateManager)_dynamicHoverStyle).TrackViewState(); 311 } 312 } 313 return _dynamicHoverStyle; 314 } 315 } 316 317 [DefaultValue("")] 318 [WebCategory("Appearance")] 319 [WebSysDescription(SR.Menu_DynamicItemFormatString)] 320 public string DynamicItemFormatString { 321 get { 322 object s = ViewState["DynamicItemFormatString"]; 323 if (s == null) { 324 return String.Empty; 325 } 326 return (string)s; 327 } 328 set { 329 ViewState["DynamicItemFormatString"] = value; 330 } 331 } 332 333 334 [ 335 WebCategory("Styles"), 336 DefaultValue(null), 337 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 338 NotifyParentProperty(true), 339 PersistenceMode(PersistenceMode.InnerProperty), 340 WebSysDescription(SR.Menu_DynamicMenuItemStyle) 341 ] 342 public MenuItemStyle DynamicMenuItemStyle { 343 get { 344 if (_dynamicItemStyle == null) { 345 _dynamicItemStyle = new MenuItemStyle(); 346 if (IsTrackingViewState) { 347 ((IStateManager)_dynamicItemStyle).TrackViewState(); 348 } 349 } 350 return _dynamicItemStyle; 351 } 352 } 353 354 355 [ 356 WebCategory("Styles"), 357 DefaultValue(null), 358 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 359 NotifyParentProperty(true), 360 PersistenceMode(PersistenceMode.InnerProperty), 361 WebSysDescription(SR.Menu_DynamicMenuStyle) 362 ] 363 public SubMenuStyle DynamicMenuStyle { 364 get { 365 if (_dynamicMenuStyle == null) { 366 _dynamicMenuStyle = new SubMenuStyle(); 367 if (IsTrackingViewState) { 368 ((IStateManager)_dynamicMenuStyle).TrackViewState(); 369 } 370 } 371 return _dynamicMenuStyle; 372 } 373 } 374 375 376 [DefaultValue("")] 377 [Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))] 378 [UrlProperty()] 379 [WebCategory("Appearance")] 380 [WebSysDescription(SR.Menu_DynamicPopoutImageUrl)] 381 public string DynamicPopOutImageUrl { 382 get { 383 object s = ViewState["DynamicPopOutImageUrl"]; 384 if (s == null) { 385 return String.Empty; 386 } 387 return (string)s; 388 } 389 set { 390 ViewState["DynamicPopOutImageUrl"] = value; 391 } 392 } 393 394 395 [WebSysDefaultValue(SR.MenuAdapter_Expand)] 396 [WebCategory("Appearance")] 397 [WebSysDescription(SR.Menu_DynamicPopoutImageText)] 398 public string DynamicPopOutImageTextFormatString { 399 get { 400 object s = ViewState["DynamicPopOutImageTextFormatString"]; 401 if (s == null) { 402 return SR.GetString(SR.MenuAdapter_Expand); 403 } 404 return (string)s; 405 } 406 set { 407 ViewState["DynamicPopOutImageTextFormatString"] = value; 408 } 409 } 410 411 412 [ 413 WebCategory("Styles"), 414 DefaultValue(null), 415 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 416 NotifyParentProperty(true), 417 PersistenceMode(PersistenceMode.InnerProperty), 418 WebSysDescription(SR.Menu_DynamicSelectedStyle) 419 ] 420 public MenuItemStyle DynamicSelectedStyle { 421 get { 422 if (_dynamicSelectedStyle == null) { 423 _dynamicSelectedStyle = new MenuItemStyle(); 424 if (IsTrackingViewState) { 425 ((IStateManager)_dynamicSelectedStyle).TrackViewState(); 426 } 427 } 428 return _dynamicSelectedStyle; 429 } 430 } 431 432 [ 433 Browsable(false), 434 DefaultValue(null), 435 PersistenceMode(PersistenceMode.InnerProperty), 436 TemplateContainer(typeof(MenuItemTemplateContainer)), 437 WebSysDescription(SR.Menu_DynamicTemplate) 438 ] 439 public ITemplate DynamicItemTemplate { 440 get { 441 return _dynamicTemplate; 442 } 443 set { 444 _dynamicTemplate = value; 445 } 446 } 447 448 449 [DefaultValue("")] 450 [Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))] 451 [UrlProperty()] 452 [WebCategory("Appearance")] 453 [WebSysDescription(SR.Menu_DynamicTopSeparatorImageUrl)] 454 public string DynamicTopSeparatorImageUrl { 455 get { 456 object s = ViewState["DynamicTopSeparatorImageUrl"]; 457 if (s == null) { 458 return string.Empty; 459 } 460 return (string)s; 461 } 462 set { 463 ViewState["DynamicTopSeparatorImageUrl"] = value; 464 } 465 } 466 467 468 [ 469 DefaultValue(0), 470 WebCategory("Appearance"), 471 WebSysDescription(SR.Menu_DynamicVerticalOffset) 472 ] 473 public int DynamicVerticalOffset { 474 get { 475 object o = ViewState["DynamicVerticalOffset"]; 476 if (o == null) { 477 return 0; 478 } 479 return (int)o; 480 } 481 set { 482 ViewState["DynamicVerticalOffset"] = value; 483 } 484 } 485 486 /// <devdoc> 487 /// A cache of urls for the built-in images. 488 /// </devdoc> 489 private string[] ImageUrls { 490 get { 491 if (_imageUrls == null) { 492 _imageUrls = new string[ImageUrlsCount]; 493 } 494 return _imageUrls; 495 } 496 } 497 498 [DefaultValue(true)] 499 [WebCategory("Appearance")] 500 [WebSysDescription(SR.Menu_IncludeStyleBlock)] 501 public bool IncludeStyleBlock { get; set; } 502 503 internal bool IsNotIE { 504 get { 505 return _isNotIE; 506 } 507 } 508 509 510 /// <devdoc> 511 /// Gets the collection of top-level nodes. 512 /// </devdoc> 513 [ 514 DefaultValue(null), 515 Editor("System.Web.UI.Design.WebControls.MenuItemCollectionEditor," + AssemblyRef.SystemDesign, typeof(UITypeEditor)), 516 PersistenceMode(PersistenceMode.InnerProperty), 517 MergableProperty(false), 518 WebSysDescription(SR.Menu_Items) 519 ] 520 public MenuItemCollection Items { 521 get { 522 return RootItem.ChildItems; 523 } 524 } 525 526 527 /// <devdoc> 528 /// Gets and sets whether the text of the items should be wrapped 529 /// </devdoc> 530 [DefaultValue(false)] 531 [WebCategory("Appearance")] 532 [WebSysDescription(SR.Menu_ItemWrap)] 533 public bool ItemWrap { 534 get { 535 object o = ViewState["ItemWrap"]; 536 if (o == null) { 537 return false; 538 } 539 return (bool)o; 540 } 541 set { 542 ViewState["ItemWrap"] = value; 543 } 544 } 545 546 547 /// <devdoc> 548 /// Gets the collection of MenuItemStyles corresponding to each level 549 /// </devdoc> 550 [ 551 DefaultValue(null), 552 Editor("System.Web.UI.Design.WebControls.MenuItemStyleCollectionEditor," + AssemblyRef.SystemDesign, typeof(UITypeEditor)), 553 PersistenceMode(PersistenceMode.InnerProperty), 554 WebCategory("Styles"), 555 WebSysDescription(SR.Menu_LevelMenuItemStyles), 556 ] 557 public MenuItemStyleCollection LevelMenuItemStyles { 558 get { 559 if (_levelMenuItemStyles == null) { 560 _levelMenuItemStyles = new MenuItemStyleCollection(); 561 if (IsTrackingViewState) { 562 ((IStateManager)_levelMenuItemStyles).TrackViewState(); 563 } 564 } 565 566 return _levelMenuItemStyles; 567 } 568 } 569 570 571 /// <devdoc> 572 /// Gets the collection of MenuItemStyles corresponding to the selected item on each level 573 /// </devdoc> 574 [ 575 DefaultValue(null), 576 Editor("System.Web.UI.Design.WebControls.MenuItemStyleCollectionEditor," + AssemblyRef.SystemDesign, typeof(UITypeEditor)), 577 PersistenceMode(PersistenceMode.InnerProperty), 578 WebCategory("Styles"), 579 WebSysDescription(SR.Menu_LevelSelectedStyles), 580 ] 581 public MenuItemStyleCollection LevelSelectedStyles { 582 get { 583 if (_levelSelectedStyles == null) { 584 _levelSelectedStyles = new MenuItemStyleCollection(); 585 if (IsTrackingViewState) { 586 ((IStateManager)_levelSelectedStyles).TrackViewState(); 587 } 588 } 589 590 return _levelSelectedStyles; 591 } 592 } 593 594 595 [ 596 DefaultValue(null), 597 Editor("System.Web.UI.Design.WebControls.SubMenuStyleCollectionEditor," + AssemblyRef.SystemDesign, typeof(UITypeEditor)), 598 PersistenceMode(PersistenceMode.InnerProperty), 599 WebCategory("Styles"), 600 WebSysDescription(SR.Menu_LevelSubMenuStyles), 601 ] 602 public SubMenuStyleCollection LevelSubMenuStyles { 603 get { 604 if (_levelStyles == null) { 605 _levelStyles = new SubMenuStyleCollection(); 606 if (IsTrackingViewState) { 607 ((IStateManager)_levelStyles).TrackViewState(); 608 } 609 } 610 611 return _levelStyles; 612 } 613 } 614 615 internal int MaximumDepth { 616 get { 617 if (_maximumDepth > 0) { 618 return _maximumDepth; 619 } 620 _maximumDepth = MaximumDynamicDisplayLevels + StaticDisplayLevels; 621 if (_maximumDepth < MaximumDynamicDisplayLevels || _maximumDepth < StaticDisplayLevels) { 622 _maximumDepth = int.MaxValue; 623 } 624 return _maximumDepth; 625 } 626 } 627 628 629 [WebCategory("Behavior")] 630 [DefaultValue(3)] 631 [Themeable(true)] 632 [WebSysDescription(SR.Menu_MaximumDynamicDisplayLevels)] 633 public int MaximumDynamicDisplayLevels { 634 get { 635 object o = ViewState["MaximumDynamicDisplayLevels"]; 636 if (o == null) { 637 return 3; 638 } 639 return (int)o; 640 } 641 set { 642 if (value < 0) { 643 throw new ArgumentOutOfRangeException("MaximumDynamicDisplayLevels", SR.GetString(SR.Menu_MaximumDynamicDisplayLevelsInvalid)); 644 } 645 // Note: we're not testing against the old value here because 646 // the setter is not the only thing that can change the underlying 647 // ViewState entry: LoadViewState modifies it directly. 648 ViewState["MaximumDynamicDisplayLevels"] = value; 649 // Reset max depth cache 650 _maximumDepth = 0; 651 // Rebind if necessary 652 if (_dataBound) { 653 _dataBound = false; 654 PerformDataBinding(); 655 } 656 } 657 } 658 659 660 [WebCategory("Layout")] 661 [DefaultValue(Orientation.Vertical)] 662 [WebSysDescription(SR.Menu_Orientation)] 663 public Orientation Orientation { 664 get { 665 object o = ViewState["Orientation"]; 666 if (o == null) { 667 return Orientation.Vertical; 668 } 669 return (Orientation)o; 670 } 671 set { 672 ViewState["Orientation"] = value; 673 } 674 } 675 676 internal PopOutPanel Panel { 677 get { 678 if (_panel == null) { 679 _panel = new PopOutPanel(this, _panelStyle); 680 if (!DesignMode) { 681 _panel.Page = Page; 682 } 683 } 684 return _panel; 685 } 686 } 687 688 [DefaultValue('/')] 689 [WebSysDescription(SR.Menu_PathSeparator)] 690 public char PathSeparator { 691 get { 692 object o = ViewState["PathSeparator"]; 693 if (o == null) { 694 return '/'; 695 } 696 return (char)o; 697 } 698 set { 699 if (value == '\0') { 700 ViewState["PathSeparator"] = null; 701 } 702 else { 703 ViewState["PathSeparator"] = value; 704 } 705 foreach (MenuItem item in Items) { 706 item.ResetValuePathRecursive(); 707 } 708 } 709 } 710 711 internal string PopoutImageUrlInternal { 712 get { 713 if (_cachedPopOutImageUrl != null) { 714 return _cachedPopOutImageUrl; 715 } 716 _cachedPopOutImageUrl = Page.ClientScript.GetWebResourceUrl(typeof(Menu), ("Menu_Popout.gif")); 717 return _cachedPopOutImageUrl; 718 } 719 } 720 721 private MenuRenderer Renderer { 722 get { 723 if (_renderer == null) { 724 switch (RenderingMode) { 725 case MenuRenderingMode.Table: 726 _renderer = new MenuRendererClassic(this); 727 break; 728 case MenuRenderingMode.List: 729 _renderer = new MenuRendererStandards(this); 730 break; 731 case MenuRenderingMode.Default: 732 if (RenderingCompatibility < VersionUtil.Framework40) { 733 _renderer = new MenuRendererClassic(this); 734 } 735 else { 736 _renderer = new MenuRendererStandards(this); 737 } 738 break; 739 default: 740 Debug.Fail("Unknown MenuRenderingMode."); 741 break; 742 } 743 } 744 return _renderer; 745 } 746 } 747 748 [ 749 WebCategory("Layout"), 750 DefaultValue(MenuRenderingMode.Default), 751 WebSysDescription(SR.Menu_RenderingMode) 752 ] 753 public MenuRenderingMode RenderingMode { 754 get { 755 return _renderingMode; 756 } 757 set { 758 if (value < MenuRenderingMode.Default || value > MenuRenderingMode.List) { 759 throw new ArgumentOutOfRangeException("value"); 760 } 761 if (_renderer != null) { 762 throw new InvalidOperationException(SR.GetString(SR.Menu_CannotChangeRenderingMode)); 763 } 764 _renderingMode = value; 765 } 766 } 767 768 /// <devdoc> 769 /// The 'virtual' root node of the menu. This menu item is never shown. 770 /// It is the parent of the "real" root items. 771 /// </devdoc> 772 internal MenuItem RootItem { 773 get { 774 if (_rootItem == null) { 775 _rootItem = new MenuItem(this, true); 776 } 777 return _rootItem; 778 } 779 } 780 781 // RootMenuItemStyle is roughly equivalent to ControlStyle.HyperLinkStyle if it existed. 782 internal Style RootMenuItemStyle { 783 get { 784 EnsureRootMenuStyle(); 785 return _rootMenuItemStyle; 786 } 787 } 788 789 [DefaultValue("")] 790 [Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))] 791 [UrlProperty()] 792 [WebCategory("Appearance")] 793 [WebSysDescription(SR.Menu_ScrollDownImageUrl)] 794 public string ScrollDownImageUrl { 795 get { 796 object s = ViewState["ScrollDownImageUrl"]; 797 if (s == null) { 798 return String.Empty; 799 } 800 return (string)s; 801 } 802 set { 803 ViewState["ScrollDownImageUrl"] = value; 804 } 805 } 806 807 internal string ScrollDownImageUrlInternal { 808 get { 809 if (_cachedScrollDownImageUrl != null) { 810 return _cachedScrollDownImageUrl; 811 } 812 _cachedScrollDownImageUrl = Page.ClientScript.GetWebResourceUrl(typeof(Menu), ("Menu_ScrollDown.gif")); 813 return _cachedScrollDownImageUrl; 814 } 815 } 816 817 818 [WebSysDefaultValue(SR.Menu_ScrollDown)] 819 [Localizable(true)] 820 [WebCategory("Appearance")] 821 [WebSysDescription(SR.Menu_ScrollDownText)] 822 public string ScrollDownText { 823 get { 824 object s = ViewState["ScrollDownText"]; 825 if (s == null) { 826 return SR.GetString(SR.Menu_ScrollDown); 827 } 828 return (string)s; 829 } 830 set { 831 ViewState["ScrollDownText"] = value; 832 } 833 } 834 835 836 [DefaultValue("")] 837 [Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))] 838 [UrlProperty()] 839 [WebCategory("Appearance")] 840 [WebSysDescription(SR.Menu_ScrollUpImageUrl)] 841 public string ScrollUpImageUrl { 842 get { 843 object s = ViewState["ScrollUpImageUrl"]; 844 if (s == null) { 845 return String.Empty; 846 } 847 return (string)s; 848 } 849 set { 850 ViewState["ScrollUpImageUrl"] = value; 851 } 852 } 853 854 internal string ScrollUpImageUrlInternal { 855 get { 856 if (_cachedScrollUpImageUrl != null) { 857 return _cachedScrollUpImageUrl; 858 } 859 _cachedScrollUpImageUrl = Page.ClientScript.GetWebResourceUrl(typeof(Menu), ("Menu_ScrollUp.gif")); 860 return _cachedScrollUpImageUrl; 861 } 862 } 863 864 865 [WebSysDefaultValue(SR.Menu_ScrollUp)] 866 [Localizable(true)] 867 [WebCategory("Appearance")] 868 [WebSysDescription(SR.Menu_ScrollUpText)] 869 public string ScrollUpText { 870 get { 871 object s = ViewState["ScrollUpText"]; 872 if (s == null) { 873 return SR.GetString(SR.Menu_ScrollUp); 874 } 875 return (string)s; 876 } 877 set { 878 ViewState["ScrollUpText"] = value; 879 } 880 } 881 882 883 /// <devdoc> 884 /// Gets and sets the Menu's selected node. 885 /// </devdoc> 886 [ 887 Browsable(false), 888 DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 889 ] 890 public MenuItem SelectedItem { 891 get { 892 return _selectedItem; 893 } 894 } 895 896 897 [Browsable(false)] 898 [DefaultValue("")] 899 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 900 public string SelectedValue { 901 get { 902 if (SelectedItem != null) { 903 return SelectedItem.Value; 904 } 905 906 return String.Empty; 907 } 908 } 909 910 911 [WebSysDefaultValue(SR.Menu_SkipLinkTextDefault)] 912 [Localizable(true)] 913 [WebCategory("Accessibility")] 914 [WebSysDescription(SR.WebControl_SkipLinkText)] 915 public string SkipLinkText { 916 get { 917 object s = ViewState["SkipLinkText"]; 918 if (s == null) { 919 return SR.GetString(SR.Menu_SkipLinkTextDefault); 920 } 921 return (string)s; 922 } 923 set { 924 ViewState["SkipLinkText"] = value; 925 } 926 } 927 928 929 [DefaultValue("")] 930 [Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))] 931 [UrlProperty()] 932 [WebCategory("Appearance")] 933 [WebSysDescription(SR.Menu_StaticBottomSeparatorImageUrl)] 934 public string StaticBottomSeparatorImageUrl { 935 get { 936 object s = ViewState["StaticBottomSeparatorImageUrl"]; 937 if (s == null) { 938 return String.Empty; 939 } 940 return (string)s; 941 } 942 set { 943 ViewState["StaticBottomSeparatorImageUrl"] = value; 944 } 945 } 946 947 948 [WebCategory("Behavior")] 949 [DefaultValue(1)] 950 [Themeable(true)] 951 [WebSysDescription(SR.Menu_StaticDisplayLevels)] 952 public int StaticDisplayLevels { 953 get { 954 object o = ViewState["StaticDisplayLevels"]; 955 if (o == null) { 956 return 1; 957 } 958 return (int)o; 959 } 960 set { 961 if (value < 1) { 962 throw new ArgumentOutOfRangeException("value"); 963 } 964 // Note: we're not testing against the old value here because 965 // the setter is not the only thing that can change the underlying 966 // ViewState entry: LoadViewState modifies it directly. 967 ViewState["StaticDisplayLevels"] = value; 968 // Reset max depth cache 969 _maximumDepth = 0; 970 // Rebind if necessary 971 if (_dataBound && !DesignMode) { 972 _dataBound = false; 973 PerformDataBinding(); 974 } 975 } 976 } 977 978 979 [ 980 DefaultValue(true), 981 WebCategory("Appearance"), 982 WebSysDescription(SR.Menu_StaticDisplayPopOutImage) 983 ] 984 public bool StaticEnableDefaultPopOutImage { 985 get { 986 object o = ViewState["StaticEnableDefaultPopOutImage"]; 987 if (o == null) { 988 return true; 989 } 990 return (bool)o; 991 } 992 set { 993 ViewState["StaticEnableDefaultPopOutImage"] = value; 994 } 995 } 996 997 998 [ 999 DefaultValue(null), 1000 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 1001 NotifyParentProperty(true), 1002 PersistenceMode(PersistenceMode.InnerProperty), 1003 WebCategory("Styles"), 1004 WebSysDescription(SR.Menu_StaticHoverStyle) 1005 ] 1006 public Style StaticHoverStyle { 1007 get { 1008 if (_staticHoverStyle == null) { 1009 _staticHoverStyle = new Style(); 1010 if (IsTrackingViewState) { 1011 ((IStateManager)_staticHoverStyle).TrackViewState(); 1012 } 1013 } 1014 return _staticHoverStyle; 1015 } 1016 } 1017 1018 [DefaultValue("")] 1019 [WebCategory("Appearance")] 1020 [WebSysDescription(SR.Menu_StaticItemFormatString)] 1021 public string StaticItemFormatString { 1022 get { 1023 object s = ViewState["StaticItemFormatString"]; 1024 if (s == null) { 1025 return String.Empty; 1026 } 1027 return (string)s; 1028 } 1029 set { 1030 ViewState["StaticItemFormatString"] = value; 1031 } 1032 } 1033 1034 1035 [ 1036 WebCategory("Styles"), 1037 DefaultValue(null), 1038 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 1039 NotifyParentProperty(true), 1040 PersistenceMode(PersistenceMode.InnerProperty), 1041 WebSysDescription(SR.Menu_StaticMenuItemStyle) 1042 ] 1043 public MenuItemStyle StaticMenuItemStyle { 1044 get { 1045 if (_staticItemStyle == null) { 1046 _staticItemStyle = new MenuItemStyle(); 1047 if (IsTrackingViewState) { 1048 ((IStateManager)_staticItemStyle).TrackViewState(); 1049 } 1050 } 1051 return _staticItemStyle; 1052 } 1053 } 1054 1055 1056 [ 1057 WebCategory("Styles"), 1058 DefaultValue(null), 1059 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 1060 NotifyParentProperty(true), 1061 PersistenceMode(PersistenceMode.InnerProperty), 1062 WebSysDescription(SR.Menu_StaticMenuStyle) 1063 ] 1064 public SubMenuStyle StaticMenuStyle { 1065 get { 1066 if (_staticMenuStyle == null) { 1067 _staticMenuStyle = new SubMenuStyle(); 1068 if (IsTrackingViewState) { 1069 ((IStateManager)_staticMenuStyle).TrackViewState(); 1070 } 1071 } 1072 return _staticMenuStyle; 1073 } 1074 } 1075 1076 1077 [DefaultValue("")] 1078 [Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))] 1079 [UrlProperty()] 1080 [WebCategory("Appearance")] 1081 [WebSysDescription(SR.Menu_StaticPopoutImageUrl)] 1082 public string StaticPopOutImageUrl { 1083 get { 1084 object s = ViewState["StaticPopOutImageUrl"]; 1085 if (s == null) { 1086 return String.Empty; 1087 } 1088 return (string)s; 1089 } 1090 set { 1091 ViewState["StaticPopOutImageUrl"] = value; 1092 } 1093 } 1094 1095 1096 [WebSysDefaultValue(SR.MenuAdapter_Expand)] 1097 [WebCategory("Appearance")] 1098 [WebSysDescription(SR.Menu_StaticPopoutImageText)] 1099 public string StaticPopOutImageTextFormatString { 1100 get { 1101 object s = ViewState["StaticPopOutImageTextFormatString"]; 1102 if (s == null) { 1103 return SR.GetString(SR.MenuAdapter_Expand); 1104 } 1105 return (string)s; 1106 } 1107 set { 1108 ViewState["StaticPopOutImageTextFormatString"] = value; 1109 } 1110 } 1111 1112 1113 [ 1114 WebCategory("Styles"), 1115 DefaultValue(null), 1116 DesignerSerializationVisibility(DesignerSerializationVisibility.Content), 1117 NotifyParentProperty(true), 1118 PersistenceMode(PersistenceMode.InnerProperty), 1119 WebSysDescription(SR.Menu_StaticSelectedStyle) 1120 ] 1121 public MenuItemStyle StaticSelectedStyle { 1122 get { 1123 if (_staticSelectedStyle == null) { 1124 _staticSelectedStyle = new MenuItemStyle(); 1125 if (IsTrackingViewState) { 1126 ((IStateManager)_staticSelectedStyle).TrackViewState(); 1127 } 1128 } 1129 return _staticSelectedStyle; 1130 } 1131 } 1132 1133 1134 [WebCategory("Appearance")] 1135 [DefaultValue(typeof(Unit), "")] 1136 [Themeable(true)] 1137 [WebSysDescription(SR.Menu_StaticSubMenuIndent)] 1138 public Unit StaticSubMenuIndent { 1139 get { 1140 object o = ViewState["StaticSubMenuIndent"]; 1141 if (o == null) { 1142 return Unit.Empty; 1143 } 1144 return (Unit)o; 1145 } 1146 set { 1147 if (value.Value < 0) { 1148 throw new ArgumentOutOfRangeException("value"); 1149 } 1150 ViewState["StaticSubMenuIndent"] = value; 1151 } 1152 } 1153 1154 [ 1155 Browsable(false), 1156 DefaultValue(null), 1157 PersistenceMode(PersistenceMode.InnerProperty), 1158 TemplateContainer(typeof(MenuItemTemplateContainer)), 1159 WebSysDescription(SR.Menu_StaticTemplate) 1160 ] 1161 public ITemplate StaticItemTemplate { 1162 get { 1163 return _staticTemplate; 1164 } 1165 set { 1166 _staticTemplate = value; 1167 } 1168 } 1169 1170 1171 [DefaultValue("")] 1172 [Editor("System.Web.UI.Design.ImageUrlEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor))] 1173 [UrlProperty()] 1174 [WebCategory("Appearance")] 1175 [WebSysDescription(SR.Menu_StaticTopSeparatorImageUrl)] 1176 public string StaticTopSeparatorImageUrl { 1177 get { 1178 object s = ViewState["StaticTopSeparatorImageUrl"]; 1179 if (s == null) { 1180 return String.Empty; 1181 } 1182 return (string)s; 1183 } 1184 set { 1185 ViewState["StaticTopSeparatorImageUrl"] = value; 1186 } 1187 } 1188 1189 1190 /// <devdoc> 1191 /// Gets and sets the target window that the MenuItems will browse to if selected 1192 /// </devdoc> 1193 [DefaultValue("")] 1194 [WebSysDescription(SR.MenuItem_Target)] 1195 public string Target { 1196 get { 1197 object s = ViewState["Target"]; 1198 if (s == null) { 1199 return String.Empty; 1200 } 1201 return (string)s; 1202 } 1203 set { 1204 ViewState["Target"] = value; 1205 } 1206 } 1207 1208 1209 protected override HtmlTextWriterTag TagKey { 1210 get { 1211 return HtmlTextWriterTag.Table; 1212 } 1213 } 1214 1215 #region events 1216 1217 /// <devdoc> 1218 /// Triggered when an item has been clicked. 1219 /// </devdoc> 1220 [WebCategory("Behavior")] 1221 [WebSysDescription(SR.Menu_MenuItemClick)] 1222 public event MenuEventHandler MenuItemClick { 1223 add { 1224 Events.AddHandler(_menuItemClickedEvent, value); 1225 } 1226 remove { 1227 Events.RemoveHandler(_menuItemClickedEvent, value); 1228 } 1229 } 1230 1231 1232 /// <devdoc> 1233 /// Triggered when a MenuItem has been databound. 1234 /// </devdoc> 1235 [WebCategory("Behavior")] 1236 [WebSysDescription(SR.Menu_MenuItemDataBound)] 1237 public event MenuEventHandler MenuItemDataBound { 1238 add { 1239 Events.AddHandler(_menuItemDataBoundEvent, value); 1240 } 1241 remove { 1242 Events.RemoveHandler(_menuItemDataBoundEvent, value); 1243 } 1244 } 1245 #endregion 1246 AddAttributesToRender(HtmlTextWriter writer)1247 protected override void AddAttributesToRender(HtmlTextWriter writer) { 1248 VerifyRenderingInServerForm(); 1249 1250 string oldAccessKey = AccessKey; 1251 try { 1252 AccessKey = String.Empty; 1253 base.AddAttributesToRender(writer); 1254 } 1255 finally { 1256 AccessKey = oldAccessKey; 1257 } 1258 } 1259 1260 // returns true if the style contains a class name AppendCssClassName(StringBuilder builder, MenuItemStyle style, bool hyperlink)1261 private static bool AppendCssClassName(StringBuilder builder, MenuItemStyle style, bool hyperlink) { 1262 bool containsClassName = false; 1263 if (style != null) { 1264 // We have to merge with any CssClass specified on the Style itself 1265 if (style.CssClass.Length != 0) { 1266 builder.Append(style.CssClass); 1267 builder.Append(' '); 1268 containsClassName = true; 1269 } 1270 1271 string className = (hyperlink ? 1272 style.HyperLinkStyle.RegisteredCssClass : 1273 style.RegisteredCssClass); 1274 if (className.Length > 0) { 1275 builder.Append(className); 1276 builder.Append(' '); 1277 } 1278 } 1279 return containsClassName; 1280 } 1281 AppendMenuCssClassName(StringBuilder builder, SubMenuStyle style)1282 private static void AppendMenuCssClassName(StringBuilder builder, SubMenuStyle style) { 1283 if (style != null) { 1284 // We have to merge with any CssClass specified on the Style itself 1285 if (style.CssClass.Length != 0) { 1286 builder.Append(style.CssClass); 1287 builder.Append(' '); 1288 } 1289 string className = style.RegisteredCssClass; 1290 if (className.Length > 0) { 1291 builder.Append(className); 1292 builder.Append(' '); 1293 } 1294 } 1295 } 1296 1297 private static T CacheGetItem<T>(List<T> cacheList, int index) where T : class { 1298 Debug.Assert(cacheList != null); 1299 if (index < cacheList.Count) return cacheList[index]; 1300 return null; 1301 } 1302 1303 private static void CacheSetItem<T>(List<T> cacheList, int index, T item) where T : class { 1304 if (cacheList.Count > index) { 1305 cacheList[index] = item; 1306 } 1307 else { 1308 for (int i = cacheList.Count; i < index; i++) { 1309 cacheList.Add(null); 1310 } 1311 cacheList.Add(item); 1312 } 1313 } 1314 CreateChildControls()1315 protected internal override void CreateChildControls() { 1316 Controls.Clear(); 1317 1318 if ((StaticItemTemplate != null) || (DynamicItemTemplate != null)) { 1319 if (RequiresDataBinding && 1320 (!String.IsNullOrEmpty(DataSourceID) || DataSource != null)) { 1321 EnsureDataBound(); 1322 } 1323 else { 1324 // Creating child controls from the Items tree 1325 CreateChildControlsFromItems(/* dataBinding */ false); 1326 ClearChildViewState(); 1327 } 1328 } 1329 } 1330 1331 CreateChildControlsFromItems(bool dataBinding)1332 private void CreateChildControlsFromItems(bool dataBinding) { 1333 if (StaticItemTemplate != null || DynamicItemTemplate != null) { 1334 int childPosition = 0; 1335 foreach (MenuItem child in Items) { 1336 CreateTemplatedControls(StaticItemTemplate, child, childPosition++, 0, dataBinding); 1337 } 1338 } 1339 } 1340 1341 /// <devdoc> 1342 /// Creates a menu node index that is unique for this menu 1343 /// </devdoc> CreateItemIndex()1344 internal int CreateItemIndex() { 1345 return _nodeIndex++; 1346 } 1347 CreateTemplatedControls(ITemplate template, MenuItem item, int position, int depth, bool dataBinding)1348 private void CreateTemplatedControls(ITemplate template, MenuItem item, int position, int depth, bool dataBinding) { 1349 1350 if (template != null) { 1351 MenuItemTemplateContainer container = new MenuItemTemplateContainer(position, item); 1352 item.Container = (MenuItemTemplateContainer)container; 1353 template.InstantiateIn(container); 1354 Controls.Add(container); 1355 if (dataBinding) { 1356 container.DataBind(); 1357 } 1358 } 1359 int childPosition = 0; 1360 foreach (MenuItem child in item.ChildItems) { 1361 int nextDepth = depth + 1; 1362 if (template == DynamicItemTemplate) { 1363 CreateTemplatedControls(DynamicItemTemplate, child, childPosition++, nextDepth, dataBinding); 1364 } 1365 else { 1366 if (nextDepth < StaticDisplayLevels) { 1367 CreateTemplatedControls(template, child, childPosition++, nextDepth, dataBinding); 1368 } 1369 else if (DynamicItemTemplate != null) { 1370 CreateTemplatedControls(DynamicItemTemplate, child, childPosition++, nextDepth, dataBinding); 1371 } 1372 } 1373 } 1374 } 1375 1376 /// Data bound controls should override PerformDataBinding instead 1377 /// of DataBind. If DataBind if overridden, the OnDataBinding and OnDataBound events will 1378 /// fire in the wrong order. However, for backwards compat on ListControl and AdRotator, we 1379 /// can't seal this method. It is sealed on all new BaseDataBoundControl-derived controls. DataBind()1380 public override sealed void DataBind() { 1381 base.DataBind(); 1382 } 1383 1384 1385 /// <devdoc> 1386 /// Databinds the specified node to the datasource 1387 /// </devdoc> DataBindItem(MenuItem item)1388 private void DataBindItem(MenuItem item) { 1389 HierarchicalDataSourceView view = GetData(item.DataPath); 1390 // Do nothing if no datasource was set 1391 if (!IsBoundUsingDataSourceID && (DataSource == null)) { 1392 return; 1393 } 1394 1395 if (view == null) { 1396 throw new InvalidOperationException(SR.GetString(SR.Menu_DataSourceReturnedNullView, ID)); 1397 } 1398 IHierarchicalEnumerable enumerable = view.Select(); 1399 item.ChildItems.Clear(); 1400 if (enumerable != null) { 1401 // If we're bound to a SiteMapDataSource, automatically select the node 1402 if (IsBoundUsingDataSourceID) { 1403 SiteMapDataSource siteMapDataSource = GetDataSource() as SiteMapDataSource; 1404 if (siteMapDataSource != null) { 1405 SiteMapNode currentNode = siteMapDataSource.Provider.CurrentNode; 1406 if (currentNode != null) { 1407 _currentSiteMapNodeUrl = currentNode.Url; 1408 } 1409 } 1410 } 1411 1412 try { 1413 DataBindRecursive(item, enumerable); 1414 } 1415 finally { 1416 _currentSiteMapNodeUrl = null; 1417 } 1418 } 1419 } 1420 1421 1422 /// <devdoc> 1423 /// Databinds recursively, using the Menu's Bindings collection, until there is no more data. 1424 /// </devdoc> DataBindRecursive(MenuItem node, IHierarchicalEnumerable enumerable)1425 private void DataBindRecursive(MenuItem node, IHierarchicalEnumerable enumerable) { 1426 // Since we are binding children, get the level below the current node's depth 1427 int depth = node.Depth + 1; 1428 1429 // Don't databind beyond the maximum specified depth 1430 if ((MaximumDynamicDisplayLevels != -1) && (depth >= MaximumDepth)) { 1431 return; 1432 } 1433 1434 foreach (object item in enumerable) { 1435 IHierarchyData data = enumerable.GetHierarchyData(item); 1436 1437 string text = null; 1438 string value = null; 1439 string navigateUrl = String.Empty; 1440 string imageUrl = String.Empty; 1441 string popOutImageUrl = String.Empty; 1442 string separatorImageUrl = String.Empty; 1443 string target = String.Empty; 1444 bool enabled = true; 1445 bool enabledSet = false; 1446 bool selectable = true; 1447 bool selectableSet = false; 1448 string toolTip = String.Empty; 1449 1450 string dataMember = String.Empty; 1451 1452 dataMember = data.Type; 1453 1454 MenuItemBinding level = DataBindings.GetBinding(dataMember, depth); 1455 1456 if (level != null) { 1457 1458 PropertyDescriptorCollection props = TypeDescriptor.GetProperties(item); 1459 1460 // Bind Text, using the static value if necessary 1461 string textField = level.TextField; 1462 if (textField.Length > 0) { 1463 PropertyDescriptor desc = props.Find(textField, true); 1464 if (desc != null) { 1465 object objData = desc.GetValue(item); 1466 if (objData != null) { 1467 if (level.FormatString.Length > 0) { 1468 text = string.Format(CultureInfo.CurrentCulture, level.FormatString, objData); 1469 } 1470 else { 1471 text = objData.ToString(); 1472 } 1473 } 1474 } 1475 else { 1476 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidDataBinding, textField, "TextField")); 1477 } 1478 } 1479 1480 if (String.IsNullOrEmpty(text) && !String.IsNullOrEmpty(level.Text)) { 1481 text = level.Text; 1482 } 1483 1484 // Bind Value, using the static value if necessary 1485 string valueField = level.ValueField; 1486 if (valueField.Length > 0) { 1487 PropertyDescriptor desc = props.Find(valueField, true); 1488 if (desc != null) { 1489 object objData = desc.GetValue(item); 1490 if (objData != null) { 1491 value = objData.ToString(); 1492 } 1493 } 1494 else { 1495 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidDataBinding, valueField, "ValueField")); 1496 } 1497 } 1498 1499 if (String.IsNullOrEmpty(value) && !String.IsNullOrEmpty(level.Value)) { 1500 value = level.Value; 1501 } 1502 1503 // Bind Target, using the static value if necessary 1504 string targetField = level.TargetField; 1505 if (targetField.Length > 0) { 1506 PropertyDescriptor desc = props.Find(targetField, true); 1507 if (desc != null) { 1508 object objData = desc.GetValue(item); 1509 if (objData != null) { 1510 target = objData.ToString(); 1511 } 1512 } 1513 else { 1514 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidDataBinding, targetField, "TargetField")); 1515 } 1516 } 1517 1518 if (String.IsNullOrEmpty(target)) { 1519 target = level.Target; 1520 } 1521 1522 // Bind ImageUrl, using the static value if necessary 1523 string imageUrlField = level.ImageUrlField; 1524 if (imageUrlField.Length > 0) { 1525 PropertyDescriptor desc = props.Find(imageUrlField, true); 1526 if (desc != null) { 1527 object objData = desc.GetValue(item); 1528 if (objData != null) { 1529 imageUrl = objData.ToString(); 1530 } 1531 } 1532 else { 1533 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidDataBinding, imageUrlField, "ImageUrlField")); 1534 } 1535 } 1536 1537 if (String.IsNullOrEmpty(imageUrl)) { 1538 imageUrl = level.ImageUrl; 1539 } 1540 1541 // Bind NavigateUrl, using the static value if necessary 1542 string navigateUrlField = level.NavigateUrlField; 1543 if (navigateUrlField.Length > 0) { 1544 PropertyDescriptor desc = props.Find(navigateUrlField, true); 1545 if (desc != null) { 1546 object objData = desc.GetValue(item); 1547 if (objData != null) { 1548 navigateUrl = objData.ToString(); 1549 } 1550 } 1551 else { 1552 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidDataBinding, navigateUrlField, "NavigateUrlField")); 1553 } 1554 } 1555 1556 if (String.IsNullOrEmpty(navigateUrl)) { 1557 navigateUrl = level.NavigateUrl; 1558 } 1559 1560 // Bind PopOutImageUrl, using the static value if necessary 1561 string popOutImageUrlField = level.PopOutImageUrlField; 1562 if (popOutImageUrlField.Length > 0) { 1563 PropertyDescriptor desc = props.Find(popOutImageUrlField, true); 1564 if (desc != null) { 1565 object objData = desc.GetValue(item); 1566 if (objData != null) { 1567 popOutImageUrl = objData.ToString(); 1568 } 1569 } 1570 else { 1571 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidDataBinding, popOutImageUrlField, "PopOutImageUrlField")); 1572 } 1573 } 1574 1575 if (String.IsNullOrEmpty(popOutImageUrl)) { 1576 popOutImageUrl = level.PopOutImageUrl; 1577 } 1578 1579 // Bind SeperatorImageUrl, using the static value if necessary 1580 string separatorImageUrlField = level.SeparatorImageUrlField; 1581 if (separatorImageUrlField.Length > 0) { 1582 PropertyDescriptor desc = props.Find(separatorImageUrlField, true); 1583 if (desc != null) { 1584 object objData = desc.GetValue(item); 1585 if (objData != null) { 1586 separatorImageUrl = objData.ToString(); 1587 } 1588 } 1589 else { 1590 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidDataBinding, separatorImageUrlField, "SeparatorImageUrlField")); 1591 } 1592 } 1593 1594 if (String.IsNullOrEmpty(separatorImageUrl)) { 1595 separatorImageUrl = level.SeparatorImageUrl; 1596 } 1597 1598 // Bind ToolTip, using the static value if necessary 1599 string toolTipField = level.ToolTipField; 1600 if (toolTipField.Length > 0) { 1601 PropertyDescriptor desc = props.Find(toolTipField, true); 1602 if (desc != null) { 1603 object objData = desc.GetValue(item); 1604 if (objData != null) { 1605 toolTip = objData.ToString(); 1606 } 1607 } 1608 else { 1609 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidDataBinding, toolTipField, "ToolTipField")); 1610 } 1611 } 1612 1613 if (String.IsNullOrEmpty(toolTip)) { 1614 toolTip = level.ToolTip; 1615 } 1616 1617 // Bind Enabled, using the static value if necessary 1618 string enabledField = level.EnabledField; 1619 if (enabledField.Length > 0) { 1620 PropertyDescriptor desc = props.Find(enabledField, true); 1621 if (desc != null) { 1622 object objData = desc.GetValue(item); 1623 if (objData != null) { 1624 if (objData is bool) { 1625 enabled = (bool)objData; 1626 enabledSet = true; 1627 } 1628 else if (bool.TryParse(objData.ToString(), out enabled)) { 1629 enabledSet = true; 1630 } 1631 } 1632 } 1633 else { 1634 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidDataBinding, enabledField, "EnabledField")); 1635 } 1636 } 1637 1638 if (!enabledSet) { 1639 enabled = level.Enabled; 1640 } 1641 1642 // Bind Selectable, using the static value if necessary 1643 string selectableField = level.SelectableField; 1644 if (selectableField.Length > 0) { 1645 PropertyDescriptor desc = props.Find(selectableField, true); 1646 if (desc != null) { 1647 object objData = desc.GetValue(item); 1648 if (objData != null) { 1649 if (objData is bool) { 1650 selectable = (bool)objData; 1651 selectableSet = true; 1652 } 1653 else if (bool.TryParse(objData.ToString(), out selectable)) { 1654 selectableSet = true; 1655 } 1656 } 1657 } 1658 else { 1659 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidDataBinding, selectableField, "SelectableField")); 1660 } 1661 } 1662 1663 if (!selectableSet) { 1664 selectable = level.Selectable; 1665 } 1666 } 1667 else if (item is INavigateUIData) { 1668 INavigateUIData navigateUIData = (INavigateUIData)item; 1669 text = navigateUIData.Name; 1670 value = navigateUIData.Value; 1671 navigateUrl = navigateUIData.NavigateUrl; 1672 if (String.IsNullOrEmpty(navigateUrl)) { 1673 selectable = false; 1674 } 1675 toolTip = navigateUIData.Description; 1676 } 1677 1678 if (text == null) { 1679 text = item.ToString(); 1680 } 1681 1682 MenuItem newItem = null; 1683 // Allow String.Empty for the text, but not null 1684 if ((text != null) || (value != null)) { 1685 newItem = new MenuItem(text, value, imageUrl, navigateUrl, target); 1686 } 1687 1688 if (newItem != null) { 1689 if (toolTip.Length > 0) { 1690 newItem.ToolTip = toolTip; 1691 } 1692 if (popOutImageUrl.Length > 0) { 1693 newItem.PopOutImageUrl = popOutImageUrl; 1694 } 1695 if (separatorImageUrl.Length > 0) { 1696 newItem.SeparatorImageUrl = separatorImageUrl; 1697 } 1698 newItem.Enabled = enabled; 1699 newItem.Selectable = selectable; 1700 1701 newItem.SetDataPath(data.Path); 1702 newItem.SetDataBound(true); 1703 1704 node.ChildItems.Add(newItem); 1705 1706 if (String.Equals(data.Path, _currentSiteMapNodeUrl, StringComparison.OrdinalIgnoreCase)) { 1707 newItem.Selected = true; 1708 } 1709 1710 // Make sure we call user code if they've hooked the populate event 1711 newItem.SetDataItem(data.Item); 1712 OnMenuItemDataBound(new MenuEventArgs(newItem)); 1713 newItem.SetDataItem(null); 1714 1715 if (data.HasChildren && (depth < MaximumDepth)) { 1716 IHierarchicalEnumerable newEnumerable = data.GetChildren(); 1717 if (newEnumerable != null) { 1718 DataBindRecursive(newItem, newEnumerable); 1719 } 1720 } 1721 } 1722 } 1723 } 1724 EnsureDataBound()1725 protected override void EnsureDataBound() { 1726 base.EnsureDataBound(); 1727 if (!_subControlsDataBound) { 1728 foreach (Control ctrl in Controls) { 1729 ctrl.DataBind(); 1730 } 1731 _subControlsDataBound = true; 1732 } 1733 } 1734 FindItem(string valuePath)1735 public MenuItem FindItem(string valuePath) { 1736 if (valuePath == null) { 1737 return null; 1738 } 1739 return Items.FindItem(valuePath.Split(PathSeparator), 0); 1740 } 1741 GetCssClassName(MenuItem item, bool hyperLink)1742 internal string GetCssClassName(MenuItem item, bool hyperLink) { 1743 bool discarded; 1744 return GetCssClassName(item, hyperLink, out discarded); 1745 } 1746 GetCssClassName(MenuItem item, bool hyperlink, out bool containsClassName)1747 internal string GetCssClassName(MenuItem item, bool hyperlink, out bool containsClassName) { 1748 if (item == null) { 1749 throw new ArgumentNullException("item"); 1750 } 1751 1752 containsClassName = false; 1753 int depth = item.Depth; 1754 string baseClassName = CacheGetItem<string>( 1755 hyperlink ? CachedMenuItemHyperLinkClassNames : CachedMenuItemClassNames, 1756 depth); 1757 if (CachedLevelsContainingCssClass.Contains(depth)) { 1758 containsClassName = true; 1759 } 1760 1761 if (!item.Selected && (baseClassName != null)) { 1762 return baseClassName; 1763 } 1764 1765 StringBuilder builder = new StringBuilder(); 1766 if (baseClassName != null) { 1767 if (!item.Selected) return baseClassName; 1768 builder.Append(baseClassName); 1769 builder.Append(' '); 1770 } 1771 else { 1772 // No cached style, so build it 1773 if (hyperlink) { 1774 builder.Append(RootMenuItemStyle.RegisteredCssClass); 1775 builder.Append(' '); 1776 } 1777 1778 if (depth < StaticDisplayLevels) { 1779 containsClassName |= AppendCssClassName(builder, _staticItemStyle, hyperlink); 1780 } 1781 else { 1782 containsClassName |= AppendCssClassName(builder, _dynamicItemStyle, hyperlink); 1783 } 1784 if ((depth < LevelMenuItemStyles.Count) && (LevelMenuItemStyles[depth] != null)) { 1785 containsClassName |= AppendCssClassName(builder, LevelMenuItemStyles[depth], hyperlink); 1786 } 1787 1788 baseClassName = builder.ToString().Trim(); 1789 CacheSetItem<string>( 1790 hyperlink ? CachedMenuItemHyperLinkClassNames : CachedMenuItemClassNames, 1791 depth, 1792 baseClassName); 1793 1794 if (containsClassName && !CachedLevelsContainingCssClass.Contains(depth)) { 1795 CachedLevelsContainingCssClass.Add(depth); 1796 } 1797 } 1798 1799 if (item.Selected) { 1800 if (depth < StaticDisplayLevels) { 1801 containsClassName |= AppendCssClassName(builder, _staticSelectedStyle, hyperlink); 1802 } 1803 else { 1804 containsClassName |= AppendCssClassName(builder, _dynamicSelectedStyle, hyperlink); 1805 } 1806 if ((depth < LevelSelectedStyles.Count) && (LevelSelectedStyles[depth] != null)) { 1807 MenuItemStyle style = LevelSelectedStyles[depth]; 1808 containsClassName |= AppendCssClassName(builder, style, hyperlink); 1809 } 1810 return builder.ToString().Trim(); 1811 } 1812 return baseClassName; 1813 } 1814 1815 /// <devdoc>Used by GetDesignModeState to find the first dynamic submenu in Items</devdoc> GetOneDynamicItem(MenuItem item)1816 private MenuItem GetOneDynamicItem(MenuItem item) { 1817 if (item.Depth >= StaticDisplayLevels) { 1818 return item; 1819 } 1820 for (int i = 0; i < item.ChildItems.Count; i++) { 1821 MenuItem result = GetOneDynamicItem(item.ChildItems[i]); 1822 if (result != null) { 1823 return result; 1824 } 1825 } 1826 return null; 1827 } 1828 1829 1830 /// <internalonly/> 1831 /// <devdoc> 1832 /// The designer can get the static and the dynamic mode html by using the 1833 /// _getDesignTimeStaticHtml and _getDesignTimeDynamicHtml defined string keys 1834 /// of the dictionary. 1835 /// </devdoc> 1836 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)] GetDesignModeState()1837 protected override IDictionary GetDesignModeState() { 1838 IDictionary dictionary = base.GetDesignModeState(); 1839 Debug.Assert(dictionary != null && DesignMode); 1840 1841 CreateChildControls(); 1842 foreach (Control c in Controls) { 1843 c.DataBind(); 1844 } 1845 1846 // Create the html for the static part 1847 using (StringWriter staticHtmlBuilder = new StringWriter(CultureInfo.CurrentCulture)) { 1848 using (HtmlTextWriter htmlWriter = GetDesignTimeWriter(staticHtmlBuilder)) { 1849 Renderer.RenderBeginTag(htmlWriter, true); 1850 Renderer.RenderContents(htmlWriter, true); 1851 Renderer.RenderEndTag(htmlWriter, true); 1852 dictionary[_getDesignTimeStaticHtml] = staticHtmlBuilder.ToString(); 1853 } 1854 } 1855 // Remember the static depth so we can lower it if necessary to make it faster and avoid overflows 1856 int oldStaticDisplayLevels = StaticDisplayLevels; 1857 try { 1858 // Find a dynamic sub-menu 1859 MenuItem dynamicSubMenu = GetOneDynamicItem(RootItem); 1860 if (dynamicSubMenu == null) { 1861 // We need to forge a whole new dynamic submenu 1862 // First lower the static display levels 1863 _dataBound = false; 1864 StaticDisplayLevels = 1; 1865 dynamicSubMenu = new MenuItem(); 1866 dynamicSubMenu.SetDepth(0); 1867 dynamicSubMenu.SetOwner(this); 1868 // Create a single dynamic submenu, with one submenu 1869 string dummyText = SR.GetString(SR.Menu_DesignTimeDummyItemText); 1870 for (int i = 0; i < 5; i++) { 1871 MenuItem newItem = new MenuItem(dummyText); 1872 if (DynamicItemTemplate != null) { 1873 MenuItemTemplateContainer container = new MenuItemTemplateContainer(i, newItem); 1874 newItem.Container = container; 1875 DynamicItemTemplate.InstantiateIn(container); 1876 container.Site = this.Site; 1877 container.DataBind(); 1878 } 1879 dynamicSubMenu.ChildItems.Add(newItem); 1880 } 1881 dynamicSubMenu.ChildItems[1].ChildItems.Add(new MenuItem()); 1882 // Delete cached styles to ensure consistency 1883 _cachedLevelsContainingCssClass = null; 1884 _cachedMenuItemStyles = null; 1885 _cachedSubMenuStyles = null; 1886 _cachedMenuItemClassNames = null; 1887 _cachedMenuItemHyperLinkClassNames = null; 1888 _cachedSubMenuClassNames = null; 1889 } 1890 else { 1891 dynamicSubMenu = dynamicSubMenu.Parent; 1892 } 1893 // Create the html for the dynamic part 1894 using (StringWriter dynamicHtmlBuilder = new StringWriter(CultureInfo.CurrentCulture)) { 1895 using (HtmlTextWriter htmlWriter = GetDesignTimeWriter(dynamicHtmlBuilder)) { 1896 // Render the control's position on the outer table 1897 Attributes.AddAttributes(htmlWriter); 1898 // Rendering a table around the div so that the designer sees it as a block 1899 htmlWriter.RenderBeginTag(HtmlTextWriterTag.Table); 1900 htmlWriter.RenderBeginTag(HtmlTextWriterTag.Tr); 1901 htmlWriter.RenderBeginTag(HtmlTextWriterTag.Td); 1902 1903 dynamicSubMenu.Render(htmlWriter, true, false, false); 1904 1905 htmlWriter.RenderEndTag(); 1906 htmlWriter.RenderEndTag(); 1907 htmlWriter.RenderEndTag(); 1908 dictionary[_getDesignTimeDynamicHtml] = dynamicHtmlBuilder.ToString(); 1909 } 1910 } 1911 } 1912 finally { 1913 if (StaticDisplayLevels != oldStaticDisplayLevels) { 1914 StaticDisplayLevels = oldStaticDisplayLevels; 1915 } 1916 } 1917 1918 return dictionary; 1919 } 1920 GetDesignTimeWriter(StringWriter stringWriter)1921 private HtmlTextWriter GetDesignTimeWriter(StringWriter stringWriter) { 1922 if (_designTimeTextWriterType == null) { 1923 return new HtmlTextWriter(stringWriter); 1924 } 1925 else { 1926 Debug.Assert(_designTimeTextWriterType.IsSubclassOf(typeof(HtmlTextWriter))); 1927 ConstructorInfo constructor = _designTimeTextWriterType.GetConstructor(new Type[] { typeof(TextWriter) }); 1928 if (constructor == null) { 1929 return new HtmlTextWriter(stringWriter); 1930 } 1931 return (HtmlTextWriter)(constructor.Invoke(new object[] { stringWriter })); 1932 } 1933 } 1934 1935 1936 /// <devdoc> 1937 /// Gets the URL for the specified image, properly pathing the image filename depending on which image it is 1938 /// </devdoc> GetImageUrl(int index)1939 internal string GetImageUrl(int index) { 1940 if (ImageUrls[index] == null) { 1941 switch (index) { 1942 case ScrollUpImageIndex: 1943 ImageUrls[index] = ScrollUpImageUrlInternal; 1944 break; 1945 case ScrollDownImageIndex: 1946 ImageUrls[index] = ScrollDownImageUrlInternal; 1947 break; 1948 case PopOutImageIndex: 1949 ImageUrls[index] = PopoutImageUrlInternal; 1950 break; 1951 } 1952 1953 ImageUrls[index] = ResolveClientUrl(ImageUrls[index]); 1954 } 1955 1956 return ImageUrls[index]; 1957 } 1958 GetMenuItemStyle(MenuItem item)1959 internal MenuItemStyle GetMenuItemStyle(MenuItem item) { 1960 if (item == null) { 1961 throw new ArgumentNullException("item"); 1962 } 1963 1964 int depth = item.Depth; 1965 MenuItemStyle typedStyle = CacheGetItem<MenuItemStyle>(CachedMenuItemStyles, depth); 1966 1967 if (!item.Selected && typedStyle != null) return typedStyle; 1968 1969 if (typedStyle == null) { 1970 typedStyle = new MenuItemStyle(); 1971 typedStyle.CopyFrom(RootMenuItemStyle); 1972 if (depth < StaticDisplayLevels) { 1973 if (_staticItemStyle != null) { 1974 TreeView.GetMergedStyle(typedStyle, _staticItemStyle); 1975 } 1976 } 1977 else if (depth >= StaticDisplayLevels && _dynamicItemStyle != null) { 1978 TreeView.GetMergedStyle(typedStyle, _dynamicItemStyle); 1979 } 1980 if ((depth < LevelMenuItemStyles.Count) && (LevelMenuItemStyles[depth] != null)) { 1981 TreeView.GetMergedStyle(typedStyle, LevelMenuItemStyles[depth]); 1982 } 1983 CacheSetItem<MenuItemStyle>(CachedMenuItemStyles, depth, typedStyle); 1984 } 1985 1986 if (item.Selected) { 1987 MenuItemStyle selectedStyle = new MenuItemStyle(); 1988 selectedStyle.CopyFrom(typedStyle); 1989 if (depth < StaticDisplayLevels) { 1990 if (_staticSelectedStyle != null) { 1991 TreeView.GetMergedStyle(selectedStyle, _staticSelectedStyle); 1992 } 1993 } 1994 else if (depth >= StaticDisplayLevels && _dynamicSelectedStyle != null) { 1995 TreeView.GetMergedStyle(selectedStyle, _dynamicSelectedStyle); 1996 } 1997 if (depth < LevelSelectedStyles.Count && LevelSelectedStyles[depth] != null) { 1998 TreeView.GetMergedStyle(selectedStyle, LevelSelectedStyles[depth]); 1999 } 2000 return selectedStyle; 2001 } 2002 return typedStyle; 2003 } 2004 GetSubMenuCssClassName(MenuItem item)2005 internal string GetSubMenuCssClassName(MenuItem item) { 2006 if (item == null) { 2007 throw new ArgumentNullException("item"); 2008 } 2009 2010 int nextDepth = item.Depth + 1; 2011 string baseClassName = CacheGetItem<string>(CachedSubMenuClassNames, nextDepth); 2012 if (baseClassName != null) return baseClassName; 2013 2014 StringBuilder builder = new StringBuilder(); 2015 if (nextDepth < StaticDisplayLevels) { 2016 AppendMenuCssClassName(builder, _staticMenuStyle); 2017 } 2018 else { 2019 SubMenuStyle subMenuStyle = _panelStyle as SubMenuStyle; 2020 if (subMenuStyle != null) { 2021 AppendMenuCssClassName(builder, subMenuStyle); 2022 } 2023 AppendMenuCssClassName(builder, _dynamicMenuStyle); 2024 } 2025 if ((nextDepth < LevelSubMenuStyles.Count) && (LevelSubMenuStyles[nextDepth] != null)) { 2026 SubMenuStyle style = LevelSubMenuStyles[nextDepth] as SubMenuStyle; 2027 AppendMenuCssClassName(builder, style); 2028 } 2029 2030 baseClassName = builder.ToString().Trim(); 2031 CacheSetItem<string>(CachedSubMenuClassNames, nextDepth, baseClassName); 2032 return baseClassName; 2033 } 2034 GetSubMenuStyle(MenuItem item)2035 internal SubMenuStyle GetSubMenuStyle(MenuItem item) { 2036 if (item == null) { 2037 throw new ArgumentNullException("item"); 2038 } 2039 2040 int nextDepth = item.Depth + 1; 2041 SubMenuStyle subMenuStyle = CacheGetItem<SubMenuStyle>(CachedSubMenuStyles, nextDepth); 2042 2043 if (subMenuStyle != null) return subMenuStyle; 2044 2045 int staticDisplayLevels = StaticDisplayLevels; 2046 if (nextDepth >= staticDisplayLevels && !DesignMode) { 2047 subMenuStyle = new PopOutPanel.PopOutPanelStyle(Panel); 2048 } 2049 else { 2050 subMenuStyle = new SubMenuStyle(); 2051 } 2052 if (nextDepth < staticDisplayLevels) { 2053 if (_staticMenuStyle != null) { 2054 subMenuStyle.CopyFrom(_staticMenuStyle); 2055 } 2056 } 2057 else if (nextDepth >= staticDisplayLevels && _dynamicMenuStyle != null) { 2058 subMenuStyle.CopyFrom(_dynamicMenuStyle); 2059 } 2060 if (_levelStyles != null && 2061 _levelStyles.Count > nextDepth && 2062 _levelStyles[nextDepth] != null) { 2063 TreeView.GetMergedStyle(subMenuStyle, _levelStyles[nextDepth]); 2064 } 2065 2066 CacheSetItem<SubMenuStyle>(CachedSubMenuStyles, nextDepth, subMenuStyle); 2067 return subMenuStyle; 2068 } 2069 EnsureRootMenuStyle()2070 internal void EnsureRootMenuStyle() { 2071 if (_rootMenuItemStyle == null) { 2072 _rootMenuItemStyle = new Style(); 2073 _rootMenuItemStyle.Font.CopyFrom(Font); 2074 if (!ForeColor.IsEmpty) { 2075 _rootMenuItemStyle.ForeColor = ForeColor; 2076 } 2077 // Not defaulting to black anymore for not entirely satisfying but reasonable reasons (VSWhidbey 356729) 2078 if (!ControlStyle.IsSet(System.Web.UI.WebControls.Style.PROP_FONT_UNDERLINE)) { 2079 _rootMenuItemStyle.Font.Underline = false; 2080 } 2081 } 2082 } 2083 LoadControlState(object savedState)2084 protected internal override void LoadControlState(object savedState) { 2085 Pair state = savedState as Pair; 2086 if (state == null) { 2087 base.LoadControlState(savedState); 2088 return; 2089 } 2090 base.LoadControlState(state.First); 2091 2092 _selectedItem = null; 2093 if (state.Second != null) { 2094 string path = state.Second as string; 2095 if (path != null) { 2096 _selectedItem = Items.FindItem(path.Split(TreeView.InternalPathSeparator), 0); 2097 } 2098 } 2099 } 2100 LoadViewState(object state)2101 protected override void LoadViewState(object state) { 2102 if (state != null) { 2103 object[] savedState = (object[])state; 2104 2105 if (savedState[1] != null) { 2106 ((IStateManager)StaticMenuItemStyle).LoadViewState(savedState[1]); 2107 } 2108 2109 if (savedState[2] != null) { 2110 ((IStateManager)StaticSelectedStyle).LoadViewState(savedState[2]); 2111 } 2112 2113 if (savedState[3] != null) { 2114 ((IStateManager)StaticHoverStyle).LoadViewState(savedState[3]); 2115 } 2116 2117 if (savedState[4] != null) { 2118 ((IStateManager)StaticMenuStyle).LoadViewState(savedState[4]); 2119 } 2120 2121 if (savedState[5] != null) { 2122 ((IStateManager)DynamicMenuItemStyle).LoadViewState(savedState[5]); 2123 } 2124 2125 if (savedState[6] != null) { 2126 ((IStateManager)DynamicSelectedStyle).LoadViewState(savedState[6]); 2127 } 2128 2129 if (savedState[7] != null) { 2130 ((IStateManager)DynamicHoverStyle).LoadViewState(savedState[7]); 2131 } 2132 2133 if (savedState[8] != null) { 2134 ((IStateManager)DynamicMenuStyle).LoadViewState(savedState[8]); 2135 } 2136 2137 if (savedState[9] != null) { 2138 ((IStateManager)LevelMenuItemStyles).LoadViewState(savedState[9]); 2139 } 2140 2141 if (savedState[10] != null) { 2142 ((IStateManager)LevelSelectedStyles).LoadViewState(savedState[10]); 2143 } 2144 2145 if (savedState[11] != null) { 2146 ((IStateManager)LevelSubMenuStyles).LoadViewState(savedState[11]); 2147 } 2148 2149 if (savedState[12] != null) { 2150 ((IStateManager)Items).LoadViewState(savedState[12]); 2151 if (!String.IsNullOrEmpty(DataSourceID) || DataSource != null) { 2152 _dataBound = true; 2153 } 2154 } 2155 2156 // Restore the core viewstate last because some property changes here could 2157 // necessitate item rebinding (for example, MaximumDynamicDisplayLevels) 2158 if (savedState[0] != null) { 2159 base.LoadViewState(savedState[0]); 2160 } 2161 } 2162 } 2163 OnBubbleEvent(object source, EventArgs e)2164 protected override bool OnBubbleEvent(object source, EventArgs e) { 2165 MenuEventArgs me = e as MenuEventArgs; 2166 if (me != null && StringUtil.EqualsIgnoreCase(me.CommandName, MenuItemClickCommandName)) { 2167 2168 // Do not take any postback into account if the menu is disabled. 2169 if (!IsEnabled) return true; 2170 2171 OnMenuItemClick(me); 2172 if (AdapterInternal != null) { 2173 MenuAdapter menuAdapter = AdapterInternal as MenuAdapter; 2174 if (menuAdapter != null) { 2175 MenuItem mi = me.Item; 2176 // Need to tell the adapter about bubbled click events 2177 // for the templated case if the item has children 2178 if (mi != null && 2179 mi.ChildItems.Count > 0 && 2180 mi.Depth + 1 >= StaticDisplayLevels) { 2181 2182 menuAdapter.SetPath(me.Item.InternalValuePath); 2183 } 2184 } 2185 } 2186 RaiseBubbleEvent(this, e); 2187 return true; 2188 } 2189 if (e is CommandEventArgs) { 2190 RaiseBubbleEvent(this, e); 2191 return true; 2192 } 2193 return false; 2194 } 2195 OnDataBinding(EventArgs e)2196 protected override void OnDataBinding(EventArgs e) { 2197 EnsureChildControls(); 2198 base.OnDataBinding(e); 2199 } 2200 OnInit(EventArgs e)2201 protected internal override void OnInit(EventArgs e) { 2202 base.OnInit(e); 2203 Page.RegisterRequiresControlState(this); 2204 } 2205 2206 OnMenuItemClick(MenuEventArgs e)2207 protected virtual void OnMenuItemClick(MenuEventArgs e) { 2208 SetSelectedItem(e.Item); 2209 MenuEventHandler handler = (MenuEventHandler)Events[_menuItemClickedEvent]; 2210 if (handler != null) { 2211 handler(this, e); 2212 } 2213 } 2214 2215 2216 /// <devdoc> 2217 /// Raises the MenuItemDataBound event 2218 /// </devdoc> OnMenuItemDataBound(MenuEventArgs e)2219 protected virtual void OnMenuItemDataBound(MenuEventArgs e) { 2220 MenuEventHandler handler = (MenuEventHandler)Events[_menuItemDataBoundEvent]; 2221 if (handler != null) { 2222 handler(this, e); 2223 } 2224 } 2225 2226 /// <devdoc> 2227 /// Overridden to register for postback, and if client script is enabled, renders out 2228 /// the necessary script and hidden field to function. 2229 /// </devdoc> OnPreRender(EventArgs e)2230 protected internal override void OnPreRender(EventArgs e) { 2231 base.OnPreRender(e); 2232 2233 if (Items.Count > 0) { 2234 Renderer.PreRender(IsEnabled); 2235 } 2236 } 2237 2238 /// <devdoc> 2239 /// Overridden to register for postback, and if client script is enabled, renders out 2240 /// the necessary script and hidden field to function. 2241 /// </devdoc> OnPreRender(EventArgs e, bool registerScript)2242 internal void OnPreRender(EventArgs e, bool registerScript) { 2243 base.OnPreRender(e); 2244 2245 if (Items.Count > 0) { 2246 Renderer.PreRender(registerScript); 2247 } 2248 } 2249 2250 /// <devdoc> 2251 /// Overridden to create all the items based on the datasource provided 2252 /// </devdoc> PerformDataBinding()2253 protected internal override void PerformDataBinding() { 2254 base.PerformDataBinding(); 2255 2256 DataBindItem(RootItem); 2257 2258 if (!DesignMode && _dataBound && 2259 String.IsNullOrEmpty(DataSourceID) && DataSource == null) { 2260 2261 Items.Clear(); 2262 Controls.Clear(); 2263 ClearChildViewState(); 2264 TrackViewState(); 2265 ChildControlsCreated = true; 2266 return; 2267 } 2268 2269 if (!String.IsNullOrEmpty(DataSourceID) || 2270 DataSource != null) { 2271 2272 Controls.Clear(); 2273 ClearChildState(); 2274 TrackViewState(); 2275 2276 CreateChildControlsFromItems(true); 2277 ChildControlsCreated = true; 2278 _dataBound = true; 2279 } 2280 else if (!_subControlsDataBound) { 2281 foreach (Control ctrl in Controls) { 2282 ctrl.DataBind(); 2283 } 2284 } 2285 _subControlsDataBound = true; 2286 } 2287 Render(HtmlTextWriter writer)2288 protected internal override void Render(HtmlTextWriter writer) { 2289 VerifyRenderingInServerForm(); 2290 2291 if (Items.Count > 0) { 2292 Renderer.RenderBeginTag(writer, false); 2293 Renderer.RenderContents(writer, false); 2294 Renderer.RenderEndTag(writer, false); 2295 } 2296 } 2297 RenderBeginTag(HtmlTextWriter writer)2298 public override void RenderBeginTag(HtmlTextWriter writer) { 2299 Renderer.RenderBeginTag(writer, false); 2300 } 2301 RenderContents(HtmlTextWriter writer)2302 protected internal override void RenderContents(HtmlTextWriter writer) { 2303 Renderer.RenderContents(writer, false); 2304 } 2305 RenderEndTag(HtmlTextWriter writer)2306 public override void RenderEndTag(HtmlTextWriter writer) { 2307 Renderer.RenderEndTag(writer, false); 2308 } 2309 ResetCachedStyles()2310 internal void ResetCachedStyles() { 2311 // Reset all these cached values so things can pick up changes in the designer 2312 if (_dynamicItemStyle != null) { 2313 _dynamicItemStyle.ResetCachedStyles(); 2314 } 2315 if (_staticItemStyle != null) { 2316 _staticItemStyle.ResetCachedStyles(); 2317 } 2318 if (_dynamicSelectedStyle != null) { 2319 _dynamicSelectedStyle.ResetCachedStyles(); 2320 } 2321 if (_staticSelectedStyle != null) { 2322 _staticSelectedStyle.ResetCachedStyles(); 2323 } 2324 if (_staticHoverStyle != null) { 2325 _staticHoverHyperLinkStyle = new HyperLinkStyle(_staticHoverStyle); 2326 } 2327 if (_dynamicHoverStyle != null) { 2328 _dynamicHoverHyperLinkStyle = new HyperLinkStyle(_dynamicHoverStyle); 2329 } 2330 2331 foreach (MenuItemStyle style in LevelMenuItemStyles) { 2332 style.ResetCachedStyles(); 2333 } 2334 2335 foreach (MenuItemStyle style in LevelSelectedStyles) { 2336 style.ResetCachedStyles(); 2337 } 2338 2339 if (_imageUrls != null) { 2340 for (int i = 0; i < _imageUrls.Length; i++) { 2341 _imageUrls[i] = null; 2342 } 2343 } 2344 2345 _cachedPopOutImageUrl = null; 2346 _cachedScrollDownImageUrl = null; 2347 _cachedScrollUpImageUrl = null; 2348 _cachedLevelsContainingCssClass = null; 2349 _cachedMenuItemClassNames = null; 2350 _cachedMenuItemHyperLinkClassNames = null; 2351 _cachedMenuItemStyles = null; 2352 _cachedSubMenuClassNames = null; 2353 _cachedSubMenuStyles = null; 2354 } 2355 SaveControlState()2356 protected internal override object SaveControlState() { 2357 object baseState = base.SaveControlState(); 2358 if (_selectedItem != null) { 2359 return new Pair(baseState, _selectedItem.InternalValuePath); 2360 } 2361 else { 2362 return baseState; 2363 } 2364 } 2365 SaveViewState()2366 protected override object SaveViewState() { 2367 object[] state = new object[13]; 2368 2369 state[0] = base.SaveViewState(); 2370 2371 bool hasViewState = (state[0] != null); 2372 2373 if (_staticItemStyle != null) { 2374 state[1] = ((IStateManager)_staticItemStyle).SaveViewState(); 2375 hasViewState |= (state[1] != null); 2376 } 2377 2378 if (_staticSelectedStyle != null) { 2379 state[2] = ((IStateManager)_staticSelectedStyle).SaveViewState(); 2380 hasViewState |= (state[2] != null); 2381 } 2382 2383 if (_staticHoverStyle != null) { 2384 state[3] = ((IStateManager)_staticHoverStyle).SaveViewState(); 2385 hasViewState |= (state[3] != null); 2386 } 2387 2388 if (_staticMenuStyle != null) { 2389 state[4] = ((IStateManager)_staticMenuStyle).SaveViewState(); 2390 hasViewState |= (state[4] != null); 2391 } 2392 2393 if (_dynamicItemStyle != null) { 2394 state[5] = ((IStateManager)_dynamicItemStyle).SaveViewState(); 2395 hasViewState |= (state[5] != null); 2396 } 2397 2398 if (_dynamicSelectedStyle != null) { 2399 state[6] = ((IStateManager)_dynamicSelectedStyle).SaveViewState(); 2400 hasViewState |= (state[6] != null); 2401 } 2402 2403 if (_dynamicHoverStyle != null) { 2404 state[7] = ((IStateManager)_dynamicHoverStyle).SaveViewState(); 2405 hasViewState |= (state[7] != null); 2406 } 2407 2408 if (_dynamicMenuStyle != null) { 2409 state[8] = ((IStateManager)_dynamicMenuStyle).SaveViewState(); 2410 hasViewState |= (state[8] != null); 2411 } 2412 2413 if (_levelMenuItemStyles != null) { 2414 state[9] = ((IStateManager)_levelMenuItemStyles).SaveViewState(); 2415 hasViewState |= (state[9] != null); 2416 } 2417 2418 if (_levelSelectedStyles != null) { 2419 state[10] = ((IStateManager)_levelSelectedStyles).SaveViewState(); 2420 hasViewState |= (state[10] != null); 2421 } 2422 2423 if (_levelStyles != null) { 2424 state[11] = ((IStateManager)_levelStyles).SaveViewState(); 2425 hasViewState |= (state[11] != null); 2426 } 2427 2428 state[12] = ((IStateManager)Items).SaveViewState(); 2429 hasViewState |= (state[12] != null); 2430 2431 if (hasViewState) { 2432 return state; 2433 } 2434 else { 2435 return null; 2436 } 2437 } 2438 2439 [SecurityPermission(SecurityAction.Demand, Unrestricted = true)] SetDesignModeState(IDictionary data)2440 protected override void SetDesignModeState(IDictionary data) { 2441 if (data.Contains("DesignTimeTextWriterType")) { 2442 Type writerType = data["DesignTimeTextWriterType"] as Type; 2443 if (writerType != null && writerType.IsSubclassOf(typeof(HtmlTextWriter))) { 2444 _designTimeTextWriterType = writerType; 2445 } 2446 } 2447 base.SetDesignModeState(data); 2448 } 2449 2450 2451 /// <devdoc> 2452 /// Allows a derived Menu to set the DataBound proprety on a node 2453 /// </devdoc> SetItemDataBound(MenuItem node, bool dataBound)2454 protected void SetItemDataBound(MenuItem node, bool dataBound) { 2455 node.SetDataBound(dataBound); 2456 } 2457 2458 2459 /// <devdoc> 2460 /// Allows a derived Menu to set the DataItem on a node 2461 /// </devdoc> SetItemDataItem(MenuItem node, object dataItem)2462 protected void SetItemDataItem(MenuItem node, object dataItem) { 2463 node.SetDataItem(dataItem); 2464 } 2465 2466 2467 /// <devdoc> 2468 /// Allows a derived Menu to set the DataPath on a node 2469 /// </devdoc> SetItemDataPath(MenuItem node, string dataPath)2470 protected void SetItemDataPath(MenuItem node, string dataPath) { 2471 node.SetDataPath(dataPath); 2472 } 2473 SetSelectedItem(MenuItem node)2474 internal void SetSelectedItem(MenuItem node) { 2475 Debug.Assert(node == null || node.Owner == this); 2476 2477 if (_selectedItem != node) { 2478 if (node != null) { 2479 if (node.Depth >= MaximumDepth) { 2480 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidDepth)); 2481 } 2482 if (!(node.IsEnabledNoOwner && node.Selectable)) { 2483 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidSelection)); 2484 } 2485 } 2486 2487 // Unselect the previously selected item 2488 if ((_selectedItem != null) && (_selectedItem.Selected)) { 2489 _selectedItem.SetSelected(false); 2490 } 2491 _selectedItem = node; 2492 // Notify the new selected item that it's now selected 2493 if ((_selectedItem != null) && !_selectedItem.Selected) { 2494 _selectedItem.SetSelected(true); 2495 } 2496 } 2497 } 2498 2499 2500 /// <internalonly/> 2501 /// <devdoc> 2502 /// Marks the starting point to begin tracking and saving changes to the 2503 /// control as part of the control viewstate. 2504 /// </devdoc> TrackViewState()2505 protected override void TrackViewState() { 2506 base.TrackViewState(); 2507 2508 if (_staticItemStyle != null) { 2509 ((IStateManager)_staticItemStyle).TrackViewState(); 2510 } 2511 if (_staticSelectedStyle != null) { 2512 ((IStateManager)_staticSelectedStyle).TrackViewState(); 2513 } 2514 if (_staticHoverStyle != null) { 2515 ((IStateManager)_staticHoverStyle).TrackViewState(); 2516 } 2517 if (_staticMenuStyle != null) { 2518 ((IStateManager)_staticMenuStyle).TrackViewState(); 2519 } 2520 if (_dynamicItemStyle != null) { 2521 ((IStateManager)_dynamicItemStyle).TrackViewState(); 2522 } 2523 if (_dynamicSelectedStyle != null) { 2524 ((IStateManager)_dynamicSelectedStyle).TrackViewState(); 2525 } 2526 if (_dynamicHoverStyle != null) { 2527 ((IStateManager)_dynamicHoverStyle).TrackViewState(); 2528 } 2529 if (_dynamicMenuStyle != null) { 2530 ((IStateManager)_dynamicMenuStyle).TrackViewState(); 2531 } 2532 if (_levelMenuItemStyles != null) { 2533 ((IStateManager)_levelMenuItemStyles).TrackViewState(); 2534 } 2535 if (_levelSelectedStyles != null) { 2536 ((IStateManager)_levelSelectedStyles).TrackViewState(); 2537 } 2538 if (_levelStyles != null) { 2539 ((IStateManager)_levelStyles).TrackViewState(); 2540 } 2541 if (_bindings != null) { 2542 ((IStateManager)_bindings).TrackViewState(); 2543 } 2544 2545 ((IStateManager)Items).TrackViewState(); 2546 } 2547 VerifyRenderingInServerForm()2548 internal void VerifyRenderingInServerForm() { 2549 if (Page != null) { 2550 Page.VerifyRenderingInServerForm(this); 2551 } 2552 } 2553 2554 #region IPostBackEventHandler implementation 2555 2556 /// <internalonly/> IPostBackEventHandler.RaisePostBackEvent(string eventArgument)2557 void IPostBackEventHandler.RaisePostBackEvent(string eventArgument) { 2558 RaisePostBackEvent(eventArgument); 2559 } 2560 RaisePostBackEvent(string eventArgument)2561 protected internal virtual void RaisePostBackEvent(string eventArgument) { 2562 ValidateEvent(UniqueID, eventArgument); 2563 2564 // Do not take any postback into account if the menu is disabled. 2565 if (!IsEnabled) return; 2566 2567 EnsureChildControls(); 2568 if (AdapterInternal != null) { 2569 IPostBackEventHandler pbeh = AdapterInternal as IPostBackEventHandler; 2570 if (pbeh != null) { 2571 pbeh.RaisePostBackEvent(eventArgument); 2572 } 2573 } 2574 else { 2575 InternalRaisePostBackEvent(eventArgument); 2576 } 2577 } 2578 InternalRaisePostBackEvent(string eventArgument)2579 internal void InternalRaisePostBackEvent(string eventArgument) { 2580 if (eventArgument.Length == 0) { 2581 return; 2582 } 2583 2584 // Get the path of the node specified in the eventArgument 2585 string nodePath = HttpUtility.HtmlDecode(eventArgument); 2586 // Check the number of separator characters in the argument (should not be more than the max depth) 2587 int matches = 0; 2588 for (int i = 0; i < nodePath.Length; i++) { 2589 if (nodePath[i] == TreeView.InternalPathSeparator) { 2590 if (++matches >= MaximumDepth) { 2591 throw new InvalidOperationException(SR.GetString(SR.Menu_InvalidDepth)); 2592 } 2593 } 2594 } 2595 // Find that node in the tree 2596 MenuItem node = Items.FindItem(nodePath.Split(TreeView.InternalPathSeparator), 0); 2597 2598 if (node != null) { 2599 OnMenuItemClick(new MenuEventArgs(node)); 2600 } 2601 } 2602 #endregion 2603 } 2604 } 2605