Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / WinForms / System / WinForms / Design / ToolStripMenuItemDesigner.cs / 5 / ToolStripMenuItemDesigner.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- /* */ [assembly: System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode", Scope = "member", Target = "System.Windows.Forms.Design.ToolStripMenuItemDesigner..ctor()")] namespace System.Windows.Forms.Design { using System.Design; using System.Runtime.InteropServices; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System; using System.Security; using System.Security.Permissions; using System.Collections; using System.ComponentModel.Design; using System.Windows.Forms; using System.Drawing; using System.Drawing.Design; using System.Windows.Forms.Design; using System.Windows.Forms.Design.Behavior; using System.ComponentModel.Design.Serialization; ////// Designer for ToolStripMenuItems. /// internal class ToolStripMenuItemDesigner : ToolStripDropDownItemDesigner { private const int GLYPHINSET=2; // // This is the typeHereNode that appears to the bottom and right // of each commited ToolStripDropDownItem // private DesignerToolStripControlHost typeHereNode; private ToolStripTemplateNode typeHereTemplateNode = null; // // This is the TemplateNode.EditorToolStrip. The editor ToolStrip is // encapsulated in a ToolStripControlHost and then added as a // ToolStripDropDownItem on the current ToolStripDropDownItems DropDown. // private DesignerToolStripControlHost commitedEditorNode; // // Actual InSitu Editor. This is created for every selected // ToolStripDropDownItem and is DISPOSED immediately after the item // comes out of InSitu edit Mode. // private ToolStripTemplateNode commitedTemplateNode; // // DesignerHost for current Component. // private IDesignerHost designerHost; private ToolStripItem parentItem = null; private ToolStripAdornerWindowService toolStripAdornerWindowService = null; private ToolStripKeyboardHandlingService keyboardHandlingService = null; //Make Selection service a class level member.. used a lot. private ISelectionService selSvc = null; //DesignerTrnasaction used for removing Items private DesignerTransaction _pendingTransaction = null; private bool fireComponentChanged = false; //indicates that we are adding new MenuItem .. private bool componentAddingFired = false; //new item index private int indexToInsertNewItem = -1; //only used by DropDownMenu, DropDown or ContextMenuStrip. private DesignerTransaction insertMenuItemTransaction; // We want one parent transaction when the item is added by InSitu editing which is now supported only for MenuItems. // This parent transaction would include // - Adding the DummyItem // - Swapping the DummyItem with the InsItu // - Committing the new Item with the text entered in the Insitu. private DesignerTransaction newMenuItemTransaction; //DropDownToInvalidate private Rectangle dropDownSizeToInvalidate = Rectangle.Empty; //DropDownToInvalidate while ComponentRemove private Rectangle boundsToInvalidateOnRemove = Rectangle.Empty; private ToolStripDropDownGlyph rootControlGlyph; private bool initialized = false; // Hook on the Undoing and Undone Events... private UndoEngine undoEngine = null; private bool undoingCalled = false; private bool addingDummyItem = false; //custom DropDown private ToolStripDropDown customDropDown = null; private bool dropDownSet = false; private SerializationStore serializedDataForDropDownItems = null; private bool dropDownSetFailed = false; ////// The ToolStripDropDownItems are the associated components. /// We want those to come with in any cut, copy opreations. /// public override System.Collections.ICollection AssociatedComponents { get { ArrayList items = new ArrayList(); // Return the list only if the DropDown is AutoGenerated. // else the DropDown property set/get will handle it. if (MenuItem.DropDown.IsAutoGenerated) { foreach (ToolStripItem item in MenuItem.DropDownItems) { DesignerToolStripControlHost addNewItem = item as DesignerToolStripControlHost; if (addNewItem == null) { items.Add(item); } } } return (ICollection)items; } } ////// ShadowProperty. /// private bool CheckOnClick { get { return (bool)ShadowProperties["CheckOnClick"]; } set { ShadowProperties["CheckOnClick"] = value; } } ////// ShadowProperty. /// private bool DoubleClickEnabled { get { return (bool)ShadowProperties["DoubleClickEnabled"]; } set { ShadowProperties["DoubleClickEnabled"] = value; } } ////// ShadowProperty. /// private ToolStripDropDown DropDown { get { return customDropDown; } set { dropDownSetFailed = false; if (IsParentDropDown(value)) { dropDownSetFailed = true; throw new ArgumentException(SR.GetString(SR.InvalidArgument, "DropDown", value.ToString())); } //Check if DropDown Exists .. and if yes then Close the DropDown if (MenuItem.DropDown != null) { RemoveTypeHereNode(MenuItem); // remove and destroy all the items... if (MenuItem.DropDown.IsAutoGenerated && MenuItem.DropDownItems.Count > 0) { //Serialize all the DropDownItems for this Item.... ComponentSerializationService serializationService = GetService(typeof(ComponentSerializationService)) as ComponentSerializationService; if (serializationService != null) { serializedDataForDropDownItems = serializationService.CreateStore(); foreach (ToolStripItem item in MenuItem.DropDownItems) { //Dont Serialize the DesignerToolStripControlHost... if (!(item is DesignerToolStripControlHost)) { serializationService.Serialize(serializedDataForDropDownItems, item); } } //close the SerializationStore to Serialize Items.. serializedDataForDropDownItems.Close(); } ToolStripItem[] items = new ToolStripItem[MenuItem.DropDownItems.Count]; MenuItem.DropDownItems.CopyTo(items, 0); //base.RaiseComponentChanging(TypeDescriptor.GetProperties(MenuItem)["DropDownItems"]); foreach (ToolStripItem item in items) { MenuItem.DropDownItems.Remove(item); designerHost.DestroyComponent(item); } //base.RaiseComponentChanged(TypeDescriptor.GetProperties(MenuItem)["DropDownItems"], null, null); } MenuItem.HideDropDown(); } // Set The DropDown MenuItem.DropDown = value; //Set the Shadow Property customDropDown = value; // If DropDown is Set to null and we have valid serializedData, then use it to recreate Items. if (value == null && !dropDownSet && serializedDataForDropDownItems != null) { try { // turn off Adding/Added events listened to by the ToolStripDesigner... ToolStripDesigner._autoAddNewItems = false; // Add Dummy Node. CreatetypeHereNode(); ComponentSerializationService serializationService = GetService(typeof(ComponentSerializationService)) as ComponentSerializationService; if (serializationService != null) { serializationService.Deserialize(serializedDataForDropDownItems); serializedDataForDropDownItems = null; } } finally { // turn on Adding/Added events listened to by the ToolStripDesigner... ToolStripDesigner._autoAddNewItems = true; } } MenuItem.DropDown.OwnerItem = MenuItem; //hook up to the Disposed event ... MenuItem.DropDown.Disposed += new EventHandler(OnDropDownDisposed); // show the dropDown. if (MenuItem.Equals(selSvc.PrimarySelection)) { //Add TypeHereNode & show the Dropdown InitializeDropDown(); } } } ////// ToolStripEditorManager used this internal property to /// Activate the editor. /// internal override ToolStripTemplateNode Editor { get { if (base.Editor != null) { return base.Editor; } if (commitedTemplateNode != null) { return commitedTemplateNode; } return typeHereTemplateNode; } set { commitedTemplateNode = value; } } ////// True if the MenuItem is on ContextMenu. /// private bool IsOnContextMenu { get { ToolStrip mainStrip = GetMainToolStrip(); if (mainStrip != null && mainStrip.Site != null && !(mainStrip is ContextMenuStrip)) { return false; } return true; } } ////// Easy method for getting to the ToolStripDropDownItem /// private ToolStripDropDownItem MenuItem { get { return ToolStripItem as ToolStripDropDownItem; } } ////// This property is true when the OwnerItem is selected during COPY & PASTE operations. /// private bool MenuItemSelected { get { // check to see if the primary selection is the ToolStrip or one of it's children. // if (selSvc != null) { object selectedItem = selSvc.PrimarySelection; ToolStripItem toolItem = null; if (selectedItem == null) { if (KeyboardHandlingService != null) { selectedItem = KeyboardHandlingService.SelectedDesignerControl; } toolItem = selectedItem as ToolStripItem; } else { toolItem = selectedItem as ToolStripItem; } if (toolItem != null) { // We always need to return the current selection if we are adding a DummyNode... if (designerHost != null) { ToolStripItemDesigner designer = designerHost.GetDesigner(toolItem) as ToolStripItemDesigner; if (designer != null) { if (designer.dummyItemAdded) { return (toolItem == MenuItem); } } } // We need to return parent if we are on DropDown... if (toolItem.IsOnDropDown && toolItem.Owner is ToolStripDropDown) { ToolStripDropDownItem parentItem = ((ToolStripDropDown)toolItem.Owner).OwnerItem as ToolStripDropDownItem; return (parentItem == MenuItem); } else { return (toolItem == MenuItem); } } else if (selectedItem is ContextMenuStrip && MenuItem.DropDown == selectedItem) { return true; } } return false; } } private ToolStripKeyboardHandlingService KeyboardHandlingService { get { if (keyboardHandlingService == null) { keyboardHandlingService = GetService(typeof(ToolStripKeyboardHandlingService)) as ToolStripKeyboardHandlingService; } return keyboardHandlingService; } } ////// ParentComponent in case of MenuItems on the DropDown is the OwnerItem of the DropDown and not the ToolStripDropDown (since the DropDowns are not sited) /// protected override IComponent ParentComponent { get { if (ToolStripItem != null) { if (!ToolStripItem.IsOnOverflow && ToolStripItem.IsOnDropDown) { ToolStripDropDown dropDown = MenuItem.Owner as ToolStripDropDown; // If the dropDown is NOT AutoGenerated then its a dropdown // the user has set or its a contextMenuStrip/ToolStripDropDownMenu/ToolStripDropDown // that has been added from the ToolBox. // In such a case dont return the ownerItem but the DropDown itself as the ParentComponent. if (dropDown != null) { if (dropDown.IsAutoGenerated) { return dropDown.OwnerItem; } else { return dropDown; } } } return base.ParentComponent; } return null; } } ///////////////////////////////////////////////////////////////////////////////////// //// //// //// Methods //// //// //// ///////////////////////////////////////////////////////////////////////////////////// ////// Adds the dummy node for InSitu Edit. /// internal void AddNewTemplateNode(ToolStripDropDown dropDown) { //Check if the DropDown contains a typehereNode.... foreach (ToolStripItem currentItem in dropDown.Items) { if (currentItem is DesignerToolStripControlHost) { typeHereNode = (DesignerToolStripControlHost)currentItem; } } if (typeHereNode != null) { dropDown.Items.Remove(typeHereNode); } // // setup the MINIToolStrip host... // typeHereTemplateNode = new ToolStripTemplateNode(Component, SR.GetString(SR.ToolStripDesignerTemplateNodeEnterText), null); int width = typeHereTemplateNode.EditorToolStrip.Width; typeHereNode = new DesignerToolStripControlHost(typeHereTemplateNode.EditorToolStrip); typeHereTemplateNode.ControlHost = typeHereNode; typeHereNode.AutoSize = false; typeHereNode.Width = width; dropDown.Items.Add(typeHereNode); } // used by morphing in ToolStripItemDesigner ... hence internal method. internal void AddItemBodyGlyph(ToolStripItem item) { if (item != null) { ToolStripItemDesigner dropDownItemDesigner = (ToolStripItemDesigner)designerHost.GetDesigner(item); if (dropDownItemDesigner != null) { Rectangle bounds = dropDownItemDesigner.GetGlyphBounds(); System.Windows.Forms.Design.Behavior.Behavior toolStripBehavior = new ToolStripItemBehavior(); // Initialize Glyph ToolStripItemGlyph bodyGlyphForddItem = new ToolStripItemGlyph(item, dropDownItemDesigner, bounds, toolStripBehavior); //Set the glyph for the item .. so that we can remove it later.... dropDownItemDesigner.bodyGlyph = bodyGlyphForddItem; //Add ItemGlyph to the Collection if (toolStripAdornerWindowService != null) { toolStripAdornerWindowService.DropDownAdorner.Glyphs.Insert(0, bodyGlyphForddItem); } } } } // Add individual item Body Glyphs private void AddBodyGlyphs(ToolStripDropDownItem item) { if (item != null) { ToolStripMenuItemDesigner itemDesigner = (ToolStripMenuItemDesigner)designerHost.GetDesigner(item); if (itemDesigner != null) { foreach (ToolStripItem ddItem in item.DropDownItems) { AddItemBodyGlyph(ddItem); } } } } ////// /// This is called by the TemplateNode to Commit the Edit. /// This function creates a NEW ToolStripDropDownItem if we are committing /// a dummy node or else just replaces the TEXT and IMAGE if we are changing /// an existing MenuItem. /// ///[SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] internal override void CommitEdit(Type type, string text, bool commit, bool enterKeyPressed, bool tabKeyPressed) { IsEditorActive = false; if (!(MenuItem.Owner is ToolStripDropDown) && base.Editor != null) //we are on Base Menustrip !! { base.CommitEdit(type, text, commit, enterKeyPressed, tabKeyPressed); } else if (commit) { int index = -1; bool dummyItem = dummyItemAdded; dummyItemAdded = false; //Invalidate DropDown.. MenuItem.DropDown.SuspendLayout(); if (commitedEditorNode != null) /// this means we have a valid node and we just changed some properties.. { index = MenuItem.DropDownItems.IndexOf(commitedEditorNode); ToolStripItem editedItem = (ToolStripItem)MenuItem.DropDownItems[index + 1]; // Remove TemplatENode MenuItem.DropDown.Items.Remove(commitedEditorNode); // Get rid of the templateNode... if (commitedTemplateNode != null) { commitedTemplateNode.CloseEditor(); commitedTemplateNode = null; } if (commitedEditorNode != null) { commitedEditorNode.Dispose(); commitedEditorNode = null; } // If we have type "-" this means the user wants to add a Separator. if (text == "-") { ToolStripItemDesigner itemDesigner = designerHost.GetDesigner(editedItem) as ToolStripItemDesigner; if (itemDesigner != null) { try { editedItem = itemDesigner.MorphCurrentItem(typeof(ToolStripSeparator)); //Remove the ActionGlyph Added by morphing RemoveItemBodyGlyph(editedItem); } catch { if (newMenuItemTransaction != null) { try { newMenuItemTransaction.Cancel(); } catch //This will cause ROLLBACK and hence throw if the project is already in DEBUG and instuEdit was Active. { } newMenuItemTransaction = null; } } finally { if (newMenuItemTransaction != null) { newMenuItemTransaction.Commit(); newMenuItemTransaction = null; } } } } else { // We are adding the item through INSITU for the first time if (dummyItem) { try { dummyItemAdded = true; CreateNewItem(type, index, text); designerHost.DestroyComponent(editedItem); // One place where we need to call this explicitly since the selection // doesnt change. // if (enterKeyPressed) { typeHereNode.SelectControl(); } } catch { if (newMenuItemTransaction != null) { try { newMenuItemTransaction.Cancel(); } catch //This will cause ROLLBACK and hence throw if the project is already in DEBUG and instuEdit was Active. { } newMenuItemTransaction = null; } } finally { if (newMenuItemTransaction != null) { newMenuItemTransaction.Commit(); newMenuItemTransaction = null; } dummyItemAdded = false; } } else //We are editing item that was already present { // put the item back... editedItem.Visible = true; //create our transaction DesignerTransaction designerTransaction = designerHost.CreateTransaction(SR.GetString(SR.ToolStripItemPropertyChangeTransaction)); try { //Change the properties PropertyDescriptor textProp = TypeDescriptor.GetProperties(editedItem)["Text"]; string oldValue = (string)textProp.GetValue(editedItem); if (textProp != null && text != oldValue) { textProp.SetValue(editedItem, text); } } catch { if (designerTransaction != null) { designerTransaction.Cancel(); designerTransaction = null; } } finally { if (designerTransaction != null) { designerTransaction.Commit(); designerTransaction = null; } } } } } else //if commitedEditorNode == null and we are in commitEdit then just add the new Item, since this item is added through dropDown. { //if no editorNode then we are commiting a NEW NODE... index = MenuItem.DropDownItems.IndexOf(typeHereNode); try { dummyItemAdded = true; CreateNewItem(type, index, text); } finally { dummyItemAdded = false; } // One place where we need to call this explicitly since the selection // doesnt change. // typeHereNode.SelectControl(); } //Invalidate DropDown.. MenuItem.DropDown.ResumeLayout(true); MenuItem.DropDown.PerformLayout(); //Reset the Glyphs after Item addition... ResetGlyphs(MenuItem); //set the selection to our new item only if item was commited via ENTER KEY in the Insitu Mode. if (selSvc != null) { if (enterKeyPressed) { ToolStripItem nextItem = null; if ((MenuItem.DropDownDirection == ToolStripDropDownDirection.AboveLeft || MenuItem.DropDownDirection == ToolStripDropDownDirection.AboveRight) && index >= 1) { nextItem = MenuItem.DropDownItems[index - 1]; } else { nextItem = MenuItem.DropDownItems[index + 1]; } if (KeyboardHandlingService != null) { if (nextItem != null) { ToolStripDropDownItem currentItem = MenuItem.DropDownItems[index] as ToolStripDropDownItem; if (currentItem != null) { currentItem.HideDropDown(); } } if (nextItem == typeHereNode) { // Put Selection on the TypeHereNode. KeyboardHandlingService.SelectedDesignerControl = nextItem; selSvc.SetSelectedComponents(null, SelectionTypes.Replace); } else { KeyboardHandlingService.SelectedDesignerControl = null; selSvc.SetSelectedComponents(new object[] { nextItem }); } } } else if (tabKeyPressed) //just select this the new Item { selSvc.SetSelectedComponents(new object[] { MenuItem.DropDownItems[index] }, SelectionTypes.Replace); } } } else //we come here if we have not committed so revert our state... { if (commitedEditorNode != null) /// we just changed some properties which we want to revert... { MenuItem.DropDown.SuspendLayout(); bool dummyItem = dummyItemAdded; dummyItemAdded = false; int index = MenuItem.DropDownItems.IndexOf(commitedEditorNode); ToolStripItem editedItem = (ToolStripItem)MenuItem.DropDownItems[index + 1]; MenuItem.DropDown.Items.Remove(commitedEditorNode); // put the item back... editedItem.Visible = true; if (commitedTemplateNode != null) { commitedTemplateNode.CloseEditor(); commitedTemplateNode = null; } if (commitedEditorNode != null) { commitedEditorNode.Dispose(); commitedEditorNode = null; } if (dummyItem) { MenuItem.DropDownItems.Remove(editedItem); try { designerHost.DestroyComponent(editedItem); } catch { if (newMenuItemTransaction != null) { try { newMenuItemTransaction.Cancel(); } catch //This will cause ROLLBACK and hence throw if the project is already in DEBUG and instuEdit was Active. { } newMenuItemTransaction = null; } } editedItem = null; } // Required to do here... MenuItem.DropDown.ResumeLayout(); //Remove the Glyphs so that Mouse Message go to the Editor if (editedItem != null) { AddItemBodyGlyph(editedItem); } if (dummyItem) { SelectionManager selMgr = (SelectionManager)GetService(typeof(SelectionManager)); /// Since the operation is cancelled and there is no change of glyphs, Set SelectionManager.NeedRefresh to false so that it doesnt REFRESH, /// when the transaction is cancelled. selMgr.NeedRefresh = false; if (newMenuItemTransaction != null) { try { dummyItemAdded = true; newMenuItemTransaction.Cancel(); newMenuItemTransaction = null; if (MenuItem.DropDownItems.Count == 0) { CreatetypeHereNode(); } } finally { dummyItemAdded = false; } } dummyItem = false; } // Added for Separators... MenuItem.DropDown.PerformLayout(); } } } /// /// Creates the dummy node for InSitu Edit. /// private void CreatetypeHereNode() { //Debug.Assert(typeHereNode == null, "Why is our dummy node valid?"); if (typeHereNode == null) { AddNewTemplateNode(MenuItem.DropDown); //Add Text for Debugging Non Sited DropDown.. if (MenuItem.DropDown.Site == null) { MenuItem.DropDown.Text = MenuItem.Name + ".DropDown"; } } else if (typeHereNode != null && MenuItem.DropDownItems.IndexOf(typeHereNode) == -1) { MenuItem.DropDown.Items.Add(typeHereNode); typeHereNode.Visible = true; } //Invalidate DropDown.. MenuItem.DropDown.PerformLayout(); } ////// /// This Function is called by EnterInSituEdit where in we Swap the typeHereNode by /// the TemplateNode (the Insitu Editor). /// Since the TemplateNode had a EditorToolStrip we can just HOST that ToolStrip /// as a ToolStripContorlHost and add it to the DropDown. /// ///private void CreateDummyMenuItem(ToolStripItem item, string text, Image image) { commitedTemplateNode = new ToolStripTemplateNode(Component, text, image); commitedTemplateNode.ActiveItem = item; int width = commitedTemplateNode.EditorToolStrip.Width; commitedEditorNode = new DesignerToolStripControlHost(commitedTemplateNode.EditorToolStrip); commitedEditorNode.AutoSize = false; commitedEditorNode.Width = width; } /// /// This helper function creates a dummyItem for Insitu editing. /// [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] private ToolStripItem CreateDummyItem(Type t, int dummyIndex) { if (designerHost == null) { Debug.Fail("Couldn't get designer host!"); return null; } ToolStripItem newItem = null; // For the "Upward DropDown" add at index +1... if (MenuItem.DropDownDirection == ToolStripDropDownDirection.AboveLeft || MenuItem.DropDownDirection == ToolStripDropDownDirection.AboveRight) { dummyIndex++; } try { // turn off Adding/Added events listened to by the ToolStripDesigner... ToolStripDesigner._autoAddNewItems = false; //Store the index into a class level member so that the componentChanged can access it indexToInsertNewItem = dummyIndex; try { //create our transaction if (newMenuItemTransaction == null) { newMenuItemTransaction = designerHost.CreateTransaction(SR.GetString(SR.ToolStripCreatingNewItemTransaction)); } fireComponentChanged = true; newItem = (ToolStripItem)designerHost.CreateComponent(t); } finally { fireComponentChanged = false; } ToolStripItemDesigner designer = designerHost.GetDesigner(newItem) as ToolStripItemDesigner; try { // ToolStripItem designer tries to set the TEXT for the item in the InitializeNewComponent() // But since we are create item thru InSitu .. we shouldnt do this. designer.InternalCreate = true; if (designer is ComponentDesigner) { ((ComponentDesigner)designer).InitializeNewComponent(null); } } finally { designer.InternalCreate = false; } } catch (InvalidOperationException ex) { CommitInsertTransaction(/*commit=*/false); if (newMenuItemTransaction != null) { newMenuItemTransaction.Cancel(); newMenuItemTransaction = null; } IUIService uiService = (IUIService)GetService(typeof(IUIService)); uiService.ShowError(ex.Message); } finally { // turn on Adding/Added events listened to by the ToolStripDesigner... ToolStripDesigner._autoAddNewItems = true; // Reset the index indexToInsertNewItem = -1; } return newItem; } ////// Asks the host to create a new DropDownItem, inserts the item /// into the collection & selects it. /// [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] private ToolStripItem CreateNewItem(Type t, int dummyIndex, string newText) { if (designerHost == null) { Debug.Fail("Couldn't get designer host!"); return null; } ToolStripItem newItem = null; // For the "Upward DropDown" add at index +1... if (MenuItem.DropDownDirection == ToolStripDropDownDirection.AboveLeft || MenuItem.DropDownDirection == ToolStripDropDownDirection.AboveRight) { dummyIndex++; } //create our transaction DesignerTransaction outerTransaction = designerHost.CreateTransaction(SR.GetString(SR.ToolStripCreatingNewItemTransaction)); try { // turn off Adding/Added events listened to by the ToolStripDesigner... ToolStripDesigner._autoAddNewItems = false; //Store the index into a class level member so that the componentChanged can access it indexToInsertNewItem = dummyIndex; try { fireComponentChanged = true; newItem = (ToolStripItem)designerHost.CreateComponent(t, ToolStripDesigner.NameFromText(newText, t, MenuItem.Site)); } finally { fireComponentChanged = false; } ToolStripItemDesigner designer = designerHost.GetDesigner(newItem) as ToolStripItemDesigner; try { // ToolStripItem designer tries to set the TEXT for the item in the InitializeNewComponent() // But since we are create item thru InSitu .. we shouldnt do this. if (!string.IsNullOrEmpty(newText) || addingDummyItem) { designer.InternalCreate = true; } if (designer is ComponentDesigner) { ((ComponentDesigner)designer).InitializeNewComponent(null); } } finally { designer.InternalCreate = false; } //Set the Text and Image.. if (newItem != null) { PropertyDescriptor textProperty = TypeDescriptor.GetProperties(newItem)["Text"]; Debug.Assert(textProperty != null, "Could not find 'Text' property in ToolStripItem."); if (textProperty != null && !string.IsNullOrEmpty(newText)) { textProperty.SetValue(newItem, newText); } } } catch { //There might be scenarios where the ComponentAdding is fired but the Added doesnt get fired due to issues like VsW: 499796. // Is such cases the InsertTransaction might be still active... // So we need to cancel that too here. CommitInsertTransaction(/*commit=*/ false); if (outerTransaction != null) { outerTransaction.Cancel(); outerTransaction = null; } } finally { if (outerTransaction != null) { outerTransaction.Commit(); outerTransaction = null; } // turn on Adding/Added events listened to by the ToolStripDesigner... ToolStripDesigner._autoAddNewItems = true; // Reset the index indexToInsertNewItem = -1; } return newItem; } ////// /// Helper function to find whether the passed in DropDownItems have same owner. /// ///private bool CheckSameOwner(ToolStripDropDownItem lastSelected, ToolStripDropDownItem currentSelected) { if (lastSelected != null && currentSelected != null) { if (lastSelected.Owner is ToolStripDropDown && currentSelected.Owner is ToolStripDropDown) { ToolStripItem ownerLastSelected = ((ToolStripDropDown)(lastSelected.Owner)).OwnerItem; ToolStripItem ownerCurrentSelected = ((ToolStripDropDown)(currentSelected.Owner)).OwnerItem; return (ownerLastSelected == ownerCurrentSelected); } } return false; } // internal method to commit any node. internal void Commit() { if (commitedTemplateNode != null && commitedTemplateNode.Active) { //Get Index of the CommitedItem.. int index = MenuItem.DropDownItems.IndexOf(commitedEditorNode); commitedTemplateNode.Commit(false, false); if (index != -1 && MenuItem.DropDownItems.Count > index) { ToolStripDropDownItem newItem = MenuItem.DropDownItems[index] as ToolStripDropDownItem; if (newItem != null) { newItem.HideDropDown(); } } } else if (typeHereTemplateNode != null && typeHereTemplateNode.Active) { typeHereTemplateNode.Commit(false, false); } // COMMIT ALL THE THE PARENT CHAIN .... ToolStripDropDownItem currentItem = MenuItem; while (currentItem != null && currentItem.Owner is ToolStripDropDown) { currentItem = (ToolStripDropDownItem)((ToolStripDropDown)(currentItem.Owner)).OwnerItem; if (currentItem != null) { ToolStripMenuItemDesigner itemDesigner = (ToolStripMenuItemDesigner)designerHost.GetDesigner(currentItem); if (itemDesigner != null) { itemDesigner.Commit(); } } } } /// /// /// Disposes of this designer. /// protected override void Dispose(bool disposing) { if (disposing) { //clean up if (selSvc != null) { selSvc.SelectionChanged -= new EventHandler(this.OnSelectionChanged); } if (undoEngine != null) { undoEngine.Undoing -= new EventHandler(this.OnUndoing); undoEngine.Undone -= new EventHandler(this.OnUndone); } if (MenuItem != null) { MenuItem.DropDown.Hide(); //Unhook the events... UnHookEvents(); } if (toolStripAdornerWindowService != null) { toolStripAdornerWindowService = null; } // unhook notifications. // IComponentChangeService componentChangeSvc = (IComponentChangeService)GetService(typeof(IComponentChangeService)); if (componentChangeSvc != null) { componentChangeSvc.ComponentRemoved -= new ComponentEventHandler(ComponentChangeSvc_ComponentRemoved); componentChangeSvc.ComponentRemoving -= new ComponentEventHandler(ComponentChangeSvc_ComponentRemoving); componentChangeSvc.ComponentAdding -= new ComponentEventHandler(ComponentChangeSvc_ComponentAdding); componentChangeSvc.ComponentAdded -= new ComponentEventHandler(ComponentChangeSvc_ComponentAdded); } if (typeHereTemplateNode != null) { typeHereTemplateNode.RollBack(); typeHereTemplateNode.CloseEditor(); typeHereTemplateNode = null; } if (typeHereNode != null) { typeHereNode.Dispose(); typeHereNode = null; } if (commitedTemplateNode != null) { commitedTemplateNode.RollBack(); commitedTemplateNode.CloseEditor(); commitedTemplateNode = null; } if (commitedEditorNode != null) { commitedEditorNode.Dispose(); commitedEditorNode = null; } if (parentItem != null) { parentItem = null; } } base.Dispose(disposing); } // When the dropDown is clicked; Commit any active insitu node. private void DropDownClick(object sender, EventArgs e) { // Commit any InsituEdit Node. if (KeyboardHandlingService != null && KeyboardHandlingService.TemplateNodeActive) { // If templateNode Active .. commit and Select it KeyboardHandlingService.ActiveTemplateNode.CommitAndSelect(); } } // re-paint required to "validate" the glyphs private void DropDownPaint(object sender, PaintEventArgs e) { //Select All requires the repaint of glyphs after the DropDown receives paint message. if (selSvc != null && MenuItem != null) { foreach (ToolStripItem item in MenuItem.DropDownItems) { if (item.Visible && selSvc.GetComponentSelected(item)) { ToolStripItemDesigner designer = designerHost.GetDesigner(item) as ToolStripItemDesigner; if (designer != null) { Rectangle r = designer.GetGlyphBounds(); ToolStripDesignerUtils.GetAdjustedBounds(item, ref r); r.Inflate(GLYPHINSET, GLYPHINSET); //this will allow any Glyphs to re-paint //after this control and its designer has painted BehaviorService b = (BehaviorService)GetService(typeof(BehaviorService)); if (b != null) { b.ProcessPaintMessage(r); } } } // When you alt-tab from VS to any other application and come back // and if the dropDown is open; then the templateNode doesnt paint. // This happens when you have another control below the dropDown which paints over the controlhost // so we need to refresh the TemplateNode in this case. DesignerToolStripControlHost controlHost = item as DesignerToolStripControlHost; if (controlHost != null) { controlHost.Control.Refresh(); } } } } // Invalidate the BehaviorService if the location changed. private void DropDownLocationChanged(object sender, EventArgs e) { // this shoulnt get fired manytimes.. only in certain case... // but in those cases its needed to REFRESH THE ENTIRE adornerWindow. ToolStripDropDown dropDown = sender as ToolStripDropDown; if (dropDown.Visible) { BehaviorService behaviorService = (BehaviorService)GetService(typeof(BehaviorService)); if (behaviorService != null) { behaviorService.Invalidate(); } } } // Change the parent when the DropDown is opening. private void DropDownItem_DropDownOpening(object sender, EventArgs e) { ToolStripDropDownItem ddi = sender as ToolStripDropDownItem; if (toolStripAdornerWindowService != null) { ddi.DropDown.TopLevel = false; ddi.DropDown.Parent = toolStripAdornerWindowService.ToolStripAdornerWindowControl; } } // Add the DropDownGlyph when the dropDown is opened. private void DropDownItem_DropDownOpened(object sender, EventArgs e) { //Add Glyphs... ToolStripDropDownItem ddi = sender as ToolStripDropDownItem; if (ddi != null) { ResetGlyphs(ddi); } // finally add Glyph for the "DropDown" Control rootControl = ddi.DropDown; if (rootControl != null) { ControlDesigner designer = designerHost.GetDesigner(designerHost.RootComponent) as ControlDesigner; if (designer != null) { rootControlGlyph = new ToolStripDropDownGlyph(rootControl.Bounds, new DropDownBehavior(designer, this)); } if (toolStripAdornerWindowService != null) { toolStripAdornerWindowService.DropDownAdorner.Glyphs.Add(rootControlGlyph); } } } // Remove the dropDownGlyph after the dropDown is closed. private void DropDownItem_DropDownClosed(object sender, EventArgs e) { ToolStripDropDownItem ddi = sender as ToolStripDropDownItem; if (ddi != null) { //Invaliate the ToolStripWindow.... for clearing the dropDowns if (toolStripAdornerWindowService != null) { if (rootControlGlyph != null && toolStripAdornerWindowService.DropDownAdorner.Glyphs.Contains(rootControlGlyph)) { toolStripAdornerWindowService.DropDownAdorner.Glyphs.Remove(rootControlGlyph); } } //Remove body Glyphs... InitializeBodyGlyphsForItems(false /*remove*/, ddi); //Unhook all the Events initialized = false; UnHookEvents(); // Check if this is a Sited-DropDown if (ddi.DropDown.Site != null || ddi.DropDownItems.Count == 1) { //Get Designer ... and call Remove on that Designer. RemoveTypeHereNode(ddi); } else if (toolStripAdornerWindowService != null) { toolStripAdornerWindowService.Invalidate(ddi.DropDown.Bounds); } } } // invalidate the AdornerWindow when the DropDown resizes private void DropDownResize(object sender, EventArgs e) { ToolStripDropDown dropDown = sender as ToolStripDropDown; if (!dummyItemAdded) { if (dropDown != null && dropDown.Visible) { //Invalidate only if new Size is LESS than old Size... if (toolStripAdornerWindowService != null && (dropDown.Width < dropDownSizeToInvalidate.Width || dropDown.Size.Height < dropDownSizeToInvalidate.Height)) { using (Region invalidatingRegion = new Region(dropDownSizeToInvalidate)) { invalidatingRegion.Exclude(dropDown.Bounds); toolStripAdornerWindowService.Invalidate(invalidatingRegion); //Invalidate BehaviorService AdornerWindow as well... but only the DropDownBounds BehaviorService b = (BehaviorService)GetService(typeof(BehaviorService)); if (b != null) { b.Invalidate(invalidatingRegion); } } } } if (toolStripAdornerWindowService != null) { if (rootControlGlyph != null && toolStripAdornerWindowService.DropDownAdorner.Glyphs.Contains(rootControlGlyph)) { toolStripAdornerWindowService.DropDownAdorner.Glyphs.Remove(rootControlGlyph); } ControlDesigner designer = designerHost.GetDesigner(designerHost.RootComponent) as ControlDesigner; if (designer != null) { rootControlGlyph = new ToolStripDropDownGlyph(dropDown.Bounds, new DropDownBehavior(designer, this)); } toolStripAdornerWindowService.DropDownAdorner.Glyphs.Add(rootControlGlyph); } } dropDownSizeToInvalidate = dropDown.Bounds; } ////// Called when a menuItem wants to go into InSitu Editing Mode. /// internal void EditTemplateNode(bool clicked) { // Refresh the state of the 'TypeHere' node to NotSelected state typeHereNode.RefreshSelectionGlyph(); // Commit any InsituEdit Node. if (KeyboardHandlingService != null && KeyboardHandlingService.TemplateNodeActive) { // If templateNode Active .. commit and Select it KeyboardHandlingService.ActiveTemplateNode.CommitAndSelect(); } // commit any existing insitu editor... if (clicked) { // We should come here for a valid parent !!! if (MenuItem == null) { return; } } // always select the parent item... // but dont redraw the control during this Selection Change as this causes flicker try { ToolStripDesigner.editTemplateNode = true; selSvc.SetSelectedComponents(new object[] { MenuItem }, SelectionTypes.Replace); } finally { ToolStripDesigner.editTemplateNode = false; } // Hide the DropDown of any previous Selection.. // First get the SelectedItem... ToolStripDropDownItem selectedItem = null; if (selSvc.PrimarySelection == null && KeyboardHandlingService != null) { ToolStripItem item = KeyboardHandlingService.SelectedDesignerControl as ToolStripItem; if (item != null) { selectedItem = ((ToolStripDropDown)item.Owner).OwnerItem as ToolStripDropDownItem; } } else { selectedItem = selSvc.PrimarySelection as ToolStripDropDownItem; } // Now Hide the DropDown and Refresh Glyphs... if (selectedItem != null && selectedItem != MenuItem) { HideSiblingDropDowns(selectedItem); } MenuItem.DropDown.SuspendLayout(); dummyItemAdded = true; int index = MenuItem.DropDownItems.IndexOf(typeHereNode); ToolStripItem newDummyItem = null; try { addingDummyItem = true; newDummyItem = CreateDummyItem(typeof(ToolStripMenuItem), index); } catch (CheckoutException checkoutException) { if (checkoutException.Equals(CheckoutException.Canceled)) { CommitInsertTransaction(/*commit=*/ false); if (newMenuItemTransaction != null) { newMenuItemTransaction.Cancel(); newMenuItemTransaction = null; } } else { throw; } } finally { dummyItemAdded = (newDummyItem != null); addingDummyItem = false; } MenuItem.DropDown.ResumeLayout(); if (newDummyItem != null) { ToolStripMenuItemDesigner newItemDesigner = designerHost.GetDesigner(newDummyItem) as ToolStripMenuItemDesigner; if (newItemDesigner != null) { newItemDesigner.InitializeDropDown(); newItemDesigner.ShowEditNode(clicked); } } } ////// Called from OnDoubleClickTimerTick to Enter in InsituMode /// private void EnterInSituMode() { //we need to tell our parent that we want to enter insitu edit mode if (MenuItem.Owner is ToolStripDropDown) { ToolStripItem ownerItem = ((ToolStripDropDown)(MenuItem.Owner)).OwnerItem; //need to inform the owner tha we want to enter insitu mode if (designerHost != null) { IDesigner designer = designerHost.GetDesigner(ownerItem); if (designer is ToolStripMenuItemDesigner) { // Need to Add Dummy Node For Direct Insitu.. MenuItem.HideDropDown(); ((ToolStripMenuItemDesigner)designer).EnterInSituEdit(MenuItem); } } } } ////// This method replaces the menItem with an in-situ TemplateNode. /// internal void EnterInSituEdit(ToolStripItem toolItem) { MenuItem.DropDown.SuspendLayout(); //Remove the Glyphs so that Mouse Message go to the Editor RemoveItemBodyGlyph(toolItem); if (toolItem == null) { return; } // we can only one Active Editor at one time. if (IsEditorActive) { return; } CreateDummyMenuItem(toolItem, toolItem.Text, toolItem.Image); int index = MenuItem.DropDownItems.IndexOf(toolItem); //swap in our insitu ToolStrip MenuItem.DropDownItems.Insert(index, commitedEditorNode); if (toolItem is ToolStripControlHost) { ((ToolStripControlHost)toolItem).Control.Visible = false; } toolItem.Visible = false; MenuItem.DropDown.ResumeLayout(); // Try Focusing the TextBox.... if (commitedTemplateNode != null) { commitedTemplateNode.FocusEditor(toolItem); } ToolStripDropDownItem dropDownItem = toolItem as ToolStripDropDownItem; if (!(dropDownItem.Owner is ToolStripDropDownMenu) && dropDownItem != null && dropDownItem.Bounds.Width < commitedEditorNode.Bounds.Width) { dropDownItem.Width = commitedEditorNode.Width; dropDownItem.DropDown.Location = new Point(dropDownItem.DropDown.Location.X + commitedEditorNode.Bounds.Width - dropDownItem.Bounds.Width, dropDownItem.DropDown.Location.Y); } IsEditorActive = true; } ////// Get the Insertion Index to drop the current drag-drop item. /// /// Returns the DropDown for this MenuItem else returns the Parent(Owner). /// protected override Component GetOwnerForActionList() { return MenuItem; } // Helper Function to get the Main ToolStrip (MenuStrip); internal override ToolStrip GetMainToolStrip() { ToolStripDropDown topmost = GetFirstDropDown(MenuItem); ToolStripItem topMostItem = (topmost == null) ? null : topmost.OwnerItem; if (topMostItem != null) { return topMostItem.Owner; } return MenuItem.Owner; } ////// /// Helper function to Hide the Active Dropdown from the given DropDownItem. /// // Standard 'catch all - rethrow critical' exception pattern [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] private void HideAllDropDowns(ToolStripDropDownItem item) { try { if (MenuItem.Owner is ToolStripDropDown) { ToolStripItem ownerItem = ((ToolStripDropDown)(MenuItem.Owner)).OwnerItem; while (item != ownerItem) { if (item.DropDown.Visible) { item.HideDropDown(); } if (item.Owner is ToolStripDropDown) { item = (ToolStripDropDownItem)((ToolStripDropDown)(item.Owner)).OwnerItem; } else { return; } } } } catch (Exception e) { if (ClientUtils.IsCriticalException(e)) { throw; } } } ////// /// Helper function to Hide the Active Dropdown for all the siblings of the given DropDownItem. /// [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] [SuppressMessage("Microsoft.Security", "CA2102:CatchNonClsCompliantExceptionsInGeneralHandlers")] private void HideSiblingDropDowns(ToolStripDropDownItem item) { try { ToolStripItem ownerItem = MenuItem; while (item != ownerItem) { item.HideDropDown(); if (item.Owner is ToolStripDropDown) { item = (ToolStripDropDownItem)((ToolStripDropDown)(item.Owner)).OwnerItem; } else { return; } } } catch (Exception e) { if (ClientUtils.IsCriticalException(e)) { throw; } } } ////// This will listen to the necessary dropDown events... now we add the events on selection and unhook when the dropDown is closed. /// internal void HookEvents() { if (MenuItem != null) { MenuItem.DropDown.Closing += new ToolStripDropDownClosingEventHandler(OnDropDownClosing); MenuItem.DropDownOpening += new EventHandler(DropDownItem_DropDownOpening); MenuItem.DropDownOpened += new EventHandler(DropDownItem_DropDownOpened); MenuItem.DropDownClosed += new EventHandler(DropDownItem_DropDownClosed); MenuItem.DropDown.Resize += new System.EventHandler(this.DropDownResize); MenuItem.DropDown.ItemAdded += new ToolStripItemEventHandler(OnItemAdded); MenuItem.DropDown.Paint += new PaintEventHandler(this.DropDownPaint); MenuItem.DropDown.Click += new EventHandler(this.DropDownClick); MenuItem.DropDown.LocationChanged += new EventHandler(this.DropDownLocationChanged); } } ////// /// Initializes the ToolStripDropDownItem Designer. /// public override void Initialize(IComponent component) { base.Initialize(component); // initialize the properties we will be shadowing // Visible = true; DoubleClickEnabled = MenuItem.DoubleClickEnabled; //hook our services selSvc = (ISelectionService)GetService(typeof(ISelectionService)); if (selSvc != null) { selSvc.SelectionChanged += new EventHandler(this.OnSelectionChanged); } //hookup to the AdornerService.. toolStripAdornerWindowService = (ToolStripAdornerWindowService)GetService(typeof(ToolStripAdornerWindowService)); designerHost = (IDesignerHost)GetService(typeof(IDesignerHost)); // Hook All the Events // HookEvents(); //Set the DoubleClickEnabled MenuItem.DoubleClickEnabled = true; // attach notifcations. // IComponentChangeService componentChangeSvc = (IComponentChangeService)GetService(typeof(IComponentChangeService)); if (componentChangeSvc != null) { componentChangeSvc.ComponentRemoved += new ComponentEventHandler(ComponentChangeSvc_ComponentRemoved); componentChangeSvc.ComponentRemoving += new ComponentEventHandler(ComponentChangeSvc_ComponentRemoving); componentChangeSvc.ComponentAdding += new ComponentEventHandler(ComponentChangeSvc_ComponentAdding); componentChangeSvc.ComponentAdded += new ComponentEventHandler(ComponentChangeSvc_ComponentAdded); } if (undoEngine == null) { undoEngine = GetService(typeof(UndoEngine)) as UndoEngine; if (undoEngine != null) { undoEngine.Undoing += new EventHandler(this.OnUndoing); undoEngine.Undone += new EventHandler(this.OnUndone); } } } // internal since the Behavior uses this when the Items are moved on the DropDown. internal void InitializeBodyGlyphsForItems(bool addGlyphs /* true for add */, ToolStripDropDownItem item) { if (addGlyphs) { AddBodyGlyphs(item); } else { RemoveBodyGlyphs(item); } } ////// Important function that initializes the dropDown with the typeHereNode , hooks the events and then shows the dropDown. /// internal void InitializeDropDown() { ToolStrip main = GetMainToolStrip(); // Check if the TopMostItem is on normal dropdown or on the overflow. ToolStripDropDown firstDropDown = GetFirstDropDown(MenuItem); if (firstDropDown != null) { ToolStripItem topMostItem = firstDropDown.OwnerItem; if ((topMostItem != null && topMostItem.GetCurrentParent() is ToolStripOverflow) && !main.CanOverflow) { return; } } if (!initialized) { // Initialize the DropDown. initialized = true; // When the DropDown is Shared the ownerItem need not be the current MenuItem // In Such a case hide the dropDown for current owner ... this will bring everything // to a sane state.. ToolStripDropDownItem currentOwner = MenuItem.DropDown.OwnerItem as ToolStripDropDownItem; if (currentOwner != null && currentOwner != MenuItem) { ToolStripMenuItemDesigner ownerdesigner = designerHost.GetDesigner(currentOwner) as ToolStripMenuItemDesigner; if (ownerdesigner != null) { ownerdesigner.RemoveTypeHereNode(currentOwner); } currentOwner.HideDropDown(); } // Check if this is a Sited-DropDown if (MenuItem.DropDown.Site != null) { ToolStripDropDownDesigner designer = designerHost.GetDesigner(MenuItem.DropDown) as ToolStripDropDownDesigner; if (designer != null) { designer.currentParent = MenuItem as ToolStripMenuItem; } } CreatetypeHereNode(); MenuItem.DropDown.TopLevel = false; //Allow Drag - Drop.... MenuItem.DropDown.AllowDrop = true; HookEvents(); MenuItem.DropDown.AutoClose = false; MenuItem.ShowDropDown(); ShowOwnerDropDown(MenuItem); //Everytime you intitalize the dropDown Reset Glyphs ResetGlyphs(MenuItem); if (!IsOnContextMenu && !dummyItemAdded) { // Refer to VsW : 487943 : Required to show the SelectionBorder when the item is selected through the PropertyGrid or Doc outline. SelectionManager selMgr = (SelectionManager)GetService(typeof(SelectionManager)); // used the cached value... if (selMgr != null) { selMgr.Refresh(); } } } } private bool IsParentDropDown(ToolStripDropDown currentDropDown) { if (currentDropDown != null) { ToolStripDropDown startDropDown = MenuItem.Owner as ToolStripDropDown; while (startDropDown != null && startDropDown != currentDropDown) { ToolStripDropDownItem ownerItem = startDropDown.OwnerItem as ToolStripDropDownItem; if (ownerItem != null) { startDropDown = ownerItem.Owner as ToolStripDropDown; } else { startDropDown = null; } } if (startDropDown == null) { return false; } return true; } return false; } ////// /// This will morph the current item to the provided type "t" of the item... /// ///internal override ToolStripItem MorphCurrentItem(Type t) { //Get the Hosting DropDown'd bounds Rectangle hostingDropDownBounds = (MenuItem.GetCurrentParent()).Bounds; //Get the currentItems DropDownBounds Rectangle itemDropDownBounds = MenuItem.DropDown.Bounds; //Remove body Glyphs... InitializeBodyGlyphsForItems(false /*remove*/, MenuItem); Rectangle boundstoInvalidate = Rectangle.Union(hostingDropDownBounds, itemDropDownBounds); ToolStripAdornerWindowService toolStripservice = toolStripAdornerWindowService; ToolStripItem newItem = base.MorphCurrentItem(t); // We loose the ToolStripWindowService after Morphing... so use the cached one. if (toolStripservice != null) { toolStripservice.Invalidate(boundstoInvalidate); toolStripservice = null; } return newItem; } /// /// Fired after a component has been added. Here, we add it to the winbar and select it. /// [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] private void ComponentChangeSvc_ComponentAdded(object sender, ComponentEventArgs e) { ToolStripItem newItem = e.Component as ToolStripItem; IComponentChangeService changeSvc = (IComponentChangeService)GetService(typeof(IComponentChangeService)); // make sure it's one of ours and on DropDown. // if (newItem != null && componentAddingFired && (MenuItemSelected || fireComponentChanged)) { componentAddingFired = false; try { if (IsOnContextMenu && MenuItem.DropDown.Site != null) { if (changeSvc != null) { MemberDescriptor member = TypeDescriptor.GetProperties(MenuItem.DropDown)["Items"]; changeSvc.OnComponentChanging(MenuItem.DropDown, member); } } else { base.RaiseComponentChanging(TypeDescriptor.GetProperties(MenuItem)["DropDownItems"]); } // Get the current count of ToolStripItems. int count = MenuItem.DropDownItems.Count; // In Cut / Copy and Paste the 'indexToInsertNewItem' is not Set and hence is -1... // so check for that value... if (indexToInsertNewItem != -1) { if (IsOnContextMenu && MenuItem.DropDown.Site != null) { MenuItem.DropDown.Items.Insert(indexToInsertNewItem, newItem); } else { MenuItem.DropDownItems.Insert(indexToInsertNewItem, newItem); } } else { // Insert Item at the current Selection... ToolStripItem selectedItem = selSvc.PrimarySelection as ToolStripItem; if (selectedItem != null && selectedItem != MenuItem) { int index = MenuItem.DropDownItems.IndexOf(selectedItem); if (MenuItem.DropDownDirection == ToolStripDropDownDirection.AboveLeft || MenuItem.DropDownDirection == ToolStripDropDownDirection.AboveRight) { // Add at the next Index in case of "Up-Directed" dropDown. if (IsOnContextMenu && MenuItem.DropDown.Site != null) { MenuItem.DropDown.Items.Insert(index + 1, newItem); } else { MenuItem.DropDownItems.Insert(index + 1, newItem); } } else { if (IsOnContextMenu && MenuItem.DropDown.Site != null) { MenuItem.DropDown.Items.Insert(index, newItem); } else { MenuItem.DropDownItems.Insert(index, newItem); } } } else { if (count > 0) { if (MenuItem.DropDownDirection != ToolStripDropDownDirection.AboveLeft && MenuItem.DropDownDirection != ToolStripDropDownDirection.AboveRight) { // ADD at Last but one, the last one being the TemplateNode always... if (IsOnContextMenu && MenuItem.DropDown.Site != null) { MenuItem.DropDown.Items.Insert(count - 1, newItem); } else { MenuItem.DropDownItems.Insert(count - 1, newItem); } } } else //count == 0 { if (IsOnContextMenu && MenuItem.DropDown.Site != null) { MenuItem.DropDown.Items.Add(newItem); } else { MenuItem.DropDownItems.Add(newItem); } } } } // If the Item is added through Undo/Redo ONLY then select the item if (undoingCalled) { if (selSvc != null) { selSvc.SetSelectedComponents(new IComponent[] { newItem } , SelectionTypes.Replace); } } ResetGlyphs(MenuItem); } catch { CommitInsertTransaction(/*commit=*/false); } finally { if (IsOnContextMenu && MenuItem.DropDown.Site != null) { if (changeSvc != null) { MemberDescriptor member = TypeDescriptor.GetProperties(MenuItem.DropDown)["Items"]; changeSvc.OnComponentChanged(MenuItem.DropDown, member, null, null); } } else { base.RaiseComponentChanged(TypeDescriptor.GetProperties(MenuItem)["DropDownItems"], null, null); } CommitInsertTransaction(/*commit=*/true); } } } private void CommitInsertTransaction(bool commit) { if (!IsOnContextMenu) { ToolStrip mainStrip = GetMainToolStrip(); ToolStripDesigner mainStripDesigner = designerHost.GetDesigner(mainStrip) as ToolStripDesigner; if (mainStripDesigner != null && mainStripDesigner.InsertTansaction != null) { if (commit) { mainStripDesigner.InsertTansaction.Commit(); } else { mainStripDesigner.InsertTansaction.Cancel(); } mainStripDesigner.InsertTansaction = null; } } else { if (insertMenuItemTransaction != null) { if (commit) { insertMenuItemTransaction.Commit(); } else { insertMenuItemTransaction.Cancel(); } insertMenuItemTransaction = null; } } } ////// Checks if the component being added is a child ToolStripItem. /// private void ComponentChangeSvc_ComponentAdding(object sender, ComponentEventArgs e) { //Dont do anything if CopyInProgress is true if (KeyboardHandlingService != null && KeyboardHandlingService.CopyInProgress) { return; } if (e.Component is ToolStripItem && (MenuItemSelected || fireComponentChanged)) { if (!IsOnContextMenu) { ToolStrip mainStrip = GetMainToolStrip(); ToolStripDesigner mainStripDesigner = designerHost.GetDesigner(mainStrip) as ToolStripDesigner; if (mainStripDesigner != null && !mainStripDesigner.EditingCollection && mainStripDesigner.InsertTansaction == null) { componentAddingFired = true; Debug.Assert(designerHost != null, "Why didn't we get a designer host?"); mainStripDesigner.InsertTansaction = designerHost.CreateTransaction(SR.GetString(SR.ToolStripInsertingIntoDropDownTransaction)); } } else //we are on ContextMenuStrip, ToolStripDropDown or ToolStripDropDownMenu.... { ToolStripItem itemAdding = e.Component as ToolStripItem; if (itemAdding != null && itemAdding.Owner == null) { componentAddingFired = true; Debug.Assert(designerHost != null, "Why didn't we get a designer host?"); insertMenuItemTransaction = designerHost.CreateTransaction(SR.GetString(SR.ToolStripInsertingIntoDropDownTransaction)); } } } } ////// After a ToolStripItem is removed, remove it from the ToolStrip and select the next item. /// private void ComponentChangeSvc_ComponentRemoved(object sender, ComponentEventArgs e) { ToolStripItem itemToBeDeleted = e.Component as ToolStripItem; if (itemToBeDeleted != null && itemToBeDeleted.IsOnDropDown) { //Get the ownerItem ToolStripDropDownItem ownerItem = (ToolStripDropDownItem)((ToolStripDropDown)(itemToBeDeleted.Owner)).OwnerItem; if (ownerItem != null && ownerItem == MenuItem) { int itemIndex = ownerItem.DropDownItems.IndexOf(itemToBeDeleted); // send notifications. // try { if (itemIndex != -1) { ownerItem.DropDownItems.Remove(itemToBeDeleted); base.RaiseComponentChanged(TypeDescriptor.GetProperties(ownerItem)["DropDownItems"], null, null); } } finally { if (_pendingTransaction != null) { _pendingTransaction.Commit(); _pendingTransaction = null; } } //Remove & Add the Glyphs ResetGlyphs(ownerItem); // select the next item or the ToolStrip itself. // if (ownerItem.DropDownItems.Count > 1) { itemIndex = Math.Min(ownerItem.DropDownItems.Count - 1, itemIndex); itemIndex = Math.Max(0, itemIndex); } else { itemIndex = -1; } // Looks like we need to invalidate the entire if (toolStripAdornerWindowService != null && boundsToInvalidateOnRemove != Rectangle.Empty) { using (Region regionToInvalidate = new Region(boundsToInvalidateOnRemove)) { regionToInvalidate.Exclude(MenuItem.DropDown.Bounds); toolStripAdornerWindowService.Invalidate(regionToInvalidate); boundsToInvalidateOnRemove = Rectangle.Empty; } } // Select the item only if Cut/Delete is pressed. if (KeyboardHandlingService != null && KeyboardHandlingService.CutOrDeleteInProgress) { if (selSvc != null && !dummyItemAdded) { IComponent targetSelection = (itemIndex == -1) ? (IComponent)ownerItem : (IComponent)ownerItem.DropDownItems[itemIndex]; // if the TemplateNode becomes the targetSelection, then set the targetSelection to null. if (targetSelection is DesignerToolStripControlHost) { KeyboardHandlingService.SelectedDesignerControl = targetSelection; KeyboardHandlingService.OwnerItemAfterCut = MenuItem; selSvc.SetSelectedComponents(null, SelectionTypes.Replace); } else { selSvc.SetSelectedComponents(new IComponent[] { targetSelection }, SelectionTypes.Replace); } } } } } } ////// Before a ToolStripItem is removed, open a transaction to batch the operation. /// private void ComponentChangeSvc_ComponentRemoving(object sender, ComponentEventArgs e) { if (dummyItemAdded) { return; } ToolStripItem itemToBeDeleted = e.Component as ToolStripItem; if (itemToBeDeleted != null && itemToBeDeleted.IsOnDropDown && itemToBeDeleted.Placement == ToolStripItemPlacement.Main) { //Get the ownerItem ToolStripDropDownItem ownerItem = (ToolStripDropDownItem)((ToolStripDropDown)(itemToBeDeleted.Owner)).OwnerItem; if (ownerItem != null && ownerItem == MenuItem) { RemoveItemBodyGlyph(itemToBeDeleted); InitializeBodyGlyphsForItems(false, ownerItem); boundsToInvalidateOnRemove = ownerItem.DropDown.Bounds; //Check if the deleted item is a dropDownItem and its DropDown is Visible. ToolStripDropDownItem dropDownItem = itemToBeDeleted as ToolStripDropDownItem; if (dropDownItem != null) { boundsToInvalidateOnRemove = Rectangle.Union(boundsToInvalidateOnRemove, dropDownItem.DropDown.Bounds); } Debug.Assert(designerHost != null, "Why didn't we get a designer host?"); Debug.Assert(_pendingTransaction == null, "Adding item with pending transaction?"); try { _pendingTransaction = designerHost.CreateTransaction(SR.GetString(SR.ToolStripDesignerTransactionRemovingItem)); base.RaiseComponentChanging(TypeDescriptor.GetProperties(ownerItem)["DropDownItems"]); } catch { if (_pendingTransaction != null) { _pendingTransaction.Cancel(); _pendingTransaction = null; } } } } } ////// /// Controls the dismissal of the drop down, here - we just cancel it /// ///private void OnDropDownClosing(object sender, ToolStripDropDownClosingEventArgs e) { //always dismiss this so we don't collapse the dropdown when the user clicks @ design time e.Cancel = (e.CloseReason == ToolStripDropDownCloseReason.ItemClicked); } /// /// When DropDown is disposed; nullify the dropDown. /// private void OnDropDownDisposed(object sender, EventArgs e) { if (MenuItem != null) { if (MenuItem.DropDown != null) { MenuItem.DropDown.Disposed -= new EventHandler(OnDropDownDisposed); } // This is necessary when the MenuItem's DropDown property is SET to something other than the default DropDown. MenuItem.DropDown = null; } } ////// When a item is added, re-arrange the elements to make sure that the templateNode is at the end.. /// private void OnItemAdded(object sender, ToolStripItemEventArgs e) { // Reshuffle the TemplateNode only for "Downward" dropdowns... if (MenuItem.DropDownDirection != ToolStripDropDownDirection.AboveLeft && MenuItem.DropDownDirection != ToolStripDropDownDirection.AboveRight) { if (typeHereNode != null && (e.Item != typeHereNode)) { int currentIndexOfEditor = MenuItem.DropDown.Items.IndexOf(typeHereNode); if (currentIndexOfEditor >= 0 && currentIndexOfEditor < MenuItem.DropDown.Items.Count - 1) { // we now know the editor is there, but isnt currently at the end of the line. // lets add it. MenuItem.DropDown.ItemAdded -= new ToolStripItemEventHandler(OnItemAdded); MenuItem.DropDown.SuspendLayout(); MenuItem.DropDown.Items.Remove(typeHereNode); MenuItem.DropDown.Items.Add(typeHereNode); MenuItem.DropDown.ResumeLayout(); MenuItem.DropDown.ItemAdded += new ToolStripItemEventHandler(OnItemAdded); } else { CreatetypeHereNode(); } } } } ////// Called during Undo (this is used for DropDown Property) /// private void OnUndone(object source, EventArgs e) { if (undoingCalled) { // If we have Undone the SETTING of DropDown Revert back to Original state. if (dropDownSet && MenuItem.DropDown.IsAutoGenerated) { ToolStrip mainStrip = GetMainToolStrip(); ToolStripDesigner mainStripDesigner = designerHost.GetDesigner(mainStrip) as ToolStripDesigner; if (mainStripDesigner != null && mainStripDesigner.CacheItems) { foreach (ToolStripItem item in mainStripDesigner.Items) { MenuItem.DropDownItems.Insert(0, item); } mainStripDesigner.CacheItems = false; } ResetGlyphs(MenuItem); } // since the dropDown is closed during UnDoing .. we need to re-open the dropDown in Undone. if (MenuItem != null && selSvc.GetComponentSelected(MenuItem)) { InitializeDropDown(); MenuItem.DropDown.PerformLayout(); } undoingCalled = false; dropDownSet = false; } // After Redo-Undo Glyphs are broken. if (selSvc.GetComponentSelected(MenuItem) && !dropDownSetFailed) { InitializeDropDown(); } } ////// Called during Undo (this is used for DropDown Property) /// private void OnUndoing(object source, EventArgs e) { if (dummyItemAdded) { return; } if (!IsOnContextMenu && MenuItem.DropDown.Visible) { MenuItem.HideDropDown(); if (!MenuItem.DropDown.IsAutoGenerated) { dropDownSet = true; ToolStrip mainStrip = GetMainToolStrip(); ToolStripDesigner mainStripDesigner = designerHost.GetDesigner(mainStrip) as ToolStripDesigner; if (mainStripDesigner != null) { mainStripDesigner.CacheItems = true; mainStripDesigner.Items.Clear(); } } undoingCalled = true; } } ////// /// Once a menuitem designer has selection - be sure to expand and collapse /// all necessary child/parent items /// Implements the Selection Paint Logic by adding Text to Tag property. /// Also Hides Unnecessary DropDowns. /// private void OnSelectionChanged(object sender, EventArgs e) { //determine if we are selected if (MenuItem == null) { return; } ISelectionService selectionSvc = sender as ISelectionService; Debug.Assert(selectionSvc != null, "No Selection Service !!"); if (selectionSvc == null) { return; } //ALWAYS COMMIT!!! if (commitedTemplateNode != null && commitedTemplateNode.Active) { commitedTemplateNode.Commit(false, false); } else if (typeHereTemplateNode != null && typeHereTemplateNode.Active) { typeHereTemplateNode.Commit(false, false); } if (MenuItem.Equals(selectionSvc.PrimarySelection)) { ArrayList origSel = ToolStripDesignerUtils.originalSelComps; if (origSel != null) { ToolStripDesignerUtils.InvalidateSelection(origSel, MenuItem, MenuItem.Site, false /*shift pressed*/); } if (IsOnContextMenu && !MenuItem.Owner.Visible) { ToolStripDropDown firstDropDown = GetFirstDropDown(MenuItem); ToolStripDropDownDesigner firstDropDownDesigner = designerHost.GetDesigner(firstDropDown) as ToolStripDropDownDesigner; if (firstDropDownDesigner != null) { InitializeDropDown(); firstDropDownDesigner.ShowMenu(); firstDropDownDesigner.AddSelectionGlyphs(); } } else { InitializeDropDown(); } //Cache original selection ICollection originalSelComps = null; if (selSvc != null) { originalSelComps = selectionSvc.GetSelectedComponents(); } // Add the TemplateNode to the Selection if it is currently Selected as the GetSelectedComponents wont do it for us. origSel = new ArrayList(originalSelComps); if (origSel.Count == 0) { if (KeyboardHandlingService != null && KeyboardHandlingService.SelectedDesignerControl != null) { origSel.Add(KeyboardHandlingService.SelectedDesignerControl); } } if (origSel.Count > 0) { ToolStripDesignerUtils.originalSelComps = origSel; } } else { object selectedObj = ((ISelectionService)sender).PrimarySelection; if (selectedObj == null) { if (KeyboardHandlingService != null) { selectedObj = KeyboardHandlingService.SelectedDesignerControl; } } ToolStripItem currentSelection = selectedObj as ToolStripItem; if (currentSelection != null) { ToolStripDropDown parent = currentSelection.Owner as ToolStripDropDown; while (parent != null) { if (parent.OwnerItem == MenuItem || parent.OwnerItem == null) { return; } else { parent = ((ToolStripItem)(parent.OwnerItem)).Owner as ToolStripDropDown; } } } if (MenuItem.DropDown.Visible) { // CASE : Check if the DropDown Selected is the one assigned to this MenuItem's DropDown property. // If MenuItem.DropDown matches the currentSelection or is the First Dropdown of any selection THEN return ToolStripDropDown selectedDropDown = selectedObj as ToolStripDropDown; if (selectedDropDown != null && MenuItem.DropDown == selectedDropDown) { return; } else { // Any ToolStripItem on the DropDown OR any of its Child DropDowns ToolStripItem item = selectedObj as ToolStripItem; if (item != null) { ToolStripDropDown parent = item.Owner as ToolStripDropDown; while (parent != null) { if (parent == MenuItem.DropDown) { return; } else { parent = ((ToolStripItem)(parent.OwnerItem)).Owner as ToolStripDropDown; } } } } // Close your own dropDown... if (MenuItem.DropDown.OwnerItem == MenuItem) { MenuItem.HideDropDown(); } } } } ////// /// Allows a designer to filter the set of properties /// the component it is designing will expose through the /// TypeDescriptor object. This method is called /// immediately before its corresponding "Post" method. /// If you are overriding this method you should call /// the base implementation before you perform your own /// filtering. /// protected override void PreFilterProperties(IDictionary properties) { base.PreFilterProperties(properties); // Handle shadowed properties // string[] shadowProps = new string[] { "Visible", "DoubleClickEnabled", "CheckOnClick", "DropDown" }; PropertyDescriptor prop; Attribute[] empty = new Attribute[0]; for (int i = 0; i < shadowProps.Length; i++) { prop = (PropertyDescriptor)properties[shadowProps[i]]; if (prop != null) { properties[shadowProps[i]] = TypeDescriptor.CreateProperty(typeof(ToolStripMenuItemDesigner), prop, empty); } } } //// Resets the ToolStripMenuItem DoubleClickEnabled to be the default visible // private void ResetDoubleClickEnabled() { DoubleClickEnabled = false; } // // Resets the ToolStripMenuItem CheckOnClick to be the default visible // private void ResetCheckOnClick() { CheckOnClick = false; } // // Resets the ToolStripMenuItem CheckOnClick to be the default visible // private void ResetDropDown() { DropDown = null; } // // Resets the ToolStripMenuItem Visible to be the default visible // private void ResetVisible() { Visible = true; } // // Restores the ToolStripMenuItem Visible to be the value set in the property grid. // private void RestoreVisible() { MenuItem.Visible = Visible; } // // Removes the TypeHere node when the DropDownCloses. // internal void RemoveTypeHereNode(ToolStripDropDownItem ownerItem) { //This will cause the DropDown to Relayout // so that during the DropDownClosed event we wont have proper Bounds to Invalidate // the ToolStripAdorner... // So for this case do it here... Rectangle bounds = ownerItem.DropDown.Bounds; if (ownerItem.DropDownItems.Count > 0 && ownerItem.DropDownItems[0] is DesignerToolStripControlHost) { ownerItem.DropDownItems.RemoveAt(0); } if (typeHereTemplateNode != null && typeHereTemplateNode.Active) { typeHereTemplateNode.RollBack(); typeHereTemplateNode.CloseEditor(); typeHereTemplateNode = null; } if (typeHereNode != null) { typeHereNode.Dispose(); typeHereNode = null; } if (toolStripAdornerWindowService != null) { toolStripAdornerWindowService.Invalidate(bounds); } } /// /// /// This private function is called to ROLLBACK the current /// Insitu editing mode. /// ///private void RollBack() { if (commitedEditorNode != null) { int index = MenuItem.DropDownItems.IndexOf(commitedEditorNode); Debug.Assert(index != -1, "Invalid Index"); ToolStripDropDownItem editedItem = (ToolStripDropDownItem)MenuItem.DropDownItems[index + 1]; if (editedItem != null) { editedItem.Visible = true; } MenuItem.DropDown.Items.Remove(commitedEditorNode); if (commitedTemplateNode != null) { commitedTemplateNode.RollBack(); commitedTemplateNode.CloseEditor(); commitedTemplateNode = null; } if (commitedEditorNode != null) { commitedEditorNode.Dispose(); commitedEditorNode = null; } } } /// /// Remove Body glyphs when the dropDown is closed. /// private void RemoveBodyGlyphs(ToolStripDropDownItem item) { if (item != null) { foreach (ToolStripItem ddItem in item.DropDownItems) { ToolStripItemDesigner dropDownItemDesigner = (ToolStripItemDesigner)designerHost.GetDesigner(ddItem); if (dropDownItemDesigner != null) { ControlBodyGlyph glyph = dropDownItemDesigner.bodyGlyph; if (glyph != null && toolStripAdornerWindowService != null && toolStripAdornerWindowService.DropDownAdorner.Glyphs.Contains(glyph)) { toolStripAdornerWindowService.DropDownAdorner.Glyphs.Remove(glyph); dropDownItemDesigner.bodyGlyph = null; } } } } } ////// Remove glyphs per item /// internal void RemoveItemBodyGlyph(ToolStripItem item) { if (item != null) { ToolStripItemDesigner itemDesigner = (ToolStripItemDesigner)designerHost.GetDesigner(item); if (itemDesigner != null) { ControlBodyGlyph glyph = itemDesigner.bodyGlyph; if (glyph != null && toolStripAdornerWindowService != null && toolStripAdornerWindowService.DropDownAdorner.Glyphs.Contains(glyph)) { toolStripAdornerWindowService.DropDownAdorner.Glyphs.Remove(glyph); itemDesigner.bodyGlyph = null; } } } } ////// Helper function to remove and then re-add the glyphs. /// internal void ResetGlyphs(ToolStripDropDownItem item) { //Reset the glyphs only if the DropDown is visible. if (item.DropDown.Visible) { InitializeBodyGlyphsForItems(false, item); InitializeBodyGlyphsForItems(true, item); } } ////// Set the Selection after a insitu edit is complete. /// internal override bool SetSelection(bool enterKeyPressed) { if (enterKeyPressed) { if (!initialized) { InitializeDropDown(); } //set the selection to our new item if (selSvc != null) { if (KeyboardHandlingService != null) { int count = 0; if (MenuItem.DropDownDirection != ToolStripDropDownDirection.AboveLeft && MenuItem.DropDownDirection != ToolStripDropDownDirection.AboveRight) { // index to the last item. count = MenuItem.DropDownItems.Count; count--; } selSvc.SetSelectedComponents(new object[] { MenuItem }, SelectionTypes.Replace); if (count >= 0) { KeyboardHandlingService.SelectedDesignerControl = MenuItem.DropDownItems[count]; selSvc.SetSelectedComponents(null, SelectionTypes.Replace); } } } return true; } return false; } ////// Returns true if the visible property should be persisted in code gen. /// private bool ShouldSerializeDoubleClickEnabled() { return (bool)ShadowProperties["DoubleClickEnabled"]; } ////// Returns true if the CheckOnClick property should be persisted in code gen. /// private bool ShouldSerializeCheckOnClick() { return (bool)ShadowProperties["CheckOnClick"]; } ////// Returns true if the CheckOnClick property should be persisted in code gen. /// private bool ShouldSerializeDropDown() { return (customDropDown != null); } ////// Returns true if the visible property should be persisted in code gen. /// private bool ShouldSerializeVisible() { return !Visible; } ////// /// This Function is called thru the ToolStripEditorManager which is listening for the /// F2 command. /// ///internal override void ShowEditNode(bool clicked) { if (MenuItem == null) { return; } try { if (MenuItem.Owner is ToolStripDropDown) { this.parentItem = ((ToolStripDropDown)(MenuItem.Owner)).OwnerItem; //need to inform the owner tha we want to enter insitu mode if (designerHost != null) { IDesigner designer = designerHost.GetDesigner(parentItem); if (designer is ToolStripMenuItemDesigner) { ((ToolStripMenuItemDesigner)designer).EnterInSituEdit(MenuItem); } } } // We come here for TOP LEVEL MENUITEM .. So call base version... else { base.ShowEditNode(clicked); } } catch (CheckoutException checkoutException) { // Do not crash on canceled checkout if (checkoutException.Equals(CheckoutException.Canceled)) { return; } else { throw; } } } /// /// /// This Function would select all items starting form oldSelection to the Current MenuItem. /// ///private void SelectItems(ToolStripDropDownItem oldSelection, ISelectionService selSvc) { ToolStripDropDown ownerDropDown = (ToolStripDropDown)MenuItem.Owner; int maxIndex = Math.Max(ownerDropDown.Items.IndexOf(oldSelection), ownerDropDown.Items.IndexOf(MenuItem)); int minIndex = Math.Min(ownerDropDown.Items.IndexOf(oldSelection), ownerDropDown.Items.IndexOf(MenuItem)); ToolStripItem[] selectedItems = new ToolStripItem[maxIndex - minIndex + 1]; int i = 0; while (minIndex <= maxIndex) { selectedItems[i] = ownerDropDown.Items[minIndex]; //((ToolStripDropDownItem)selectedItems[i]).HideDropDown(); i++; minIndex++; } selSvc.SetSelectedComponents(selectedItems); } /// /// /// Shows ALL the owner DropDowns if passed in MenuItem is Selected /// ///internal void ShowOwnerDropDown(ToolStripDropDownItem currentSelection) { // We MIGHT HAVE TO START TOP - DOWN Instead of BOTTOM-UP. // Sometimes we DONT get the Owner POPUP and hence all the popup are parented to // Wrong guy. while (currentSelection != null && currentSelection.Owner is ToolStripDropDown) { currentSelection = (ToolStripDropDownItem)((ToolStripDropDown)(currentSelection.Owner)).OwnerItem; if (currentSelection != null && !currentSelection.DropDown.Visible) { ToolStripMenuItemDesigner currentSelectionDesigner = designerHost.GetDesigner(currentSelection) as ToolStripMenuItemDesigner; if (currentSelectionDesigner != null) { currentSelectionDesigner.InitializeDropDown(); } } } } /// /// This will listen to the necessary dropDown events... now we add the events on selection and unhook when the dropDown is closed. /// internal void UnHookEvents() { if (MenuItem != null) { MenuItem.DropDown.Closing -= new ToolStripDropDownClosingEventHandler(OnDropDownClosing); MenuItem.DropDownOpening -= new EventHandler(DropDownItem_DropDownOpening); MenuItem.DropDownOpened -= new EventHandler(DropDownItem_DropDownOpened); MenuItem.DropDownClosed -= new EventHandler(DropDownItem_DropDownClosed); MenuItem.DropDown.Resize -= new System.EventHandler(this.DropDownResize); MenuItem.DropDown.ItemAdded -= new ToolStripItemEventHandler(OnItemAdded); MenuItem.DropDown.Paint -= new PaintEventHandler(this.DropDownPaint); MenuItem.DropDown.LocationChanged -= new EventHandler(this.DropDownLocationChanged); MenuItem.DropDown.Click -= new EventHandler(this.DropDownClick); } } ////// The glyph we put over the items. Basically this sets the hit-testable area of the item itself. /// internal class ToolStripDropDownGlyph : Glyph { private Rectangle _bounds; internal ToolStripDropDownGlyph(Rectangle bounds, System.Windows.Forms.Design.Behavior.Behavior b) : base(b) { _bounds = bounds; } ////// /// Abstract method that forces Glyph implementations to provide /// hit test logic. Given any point - if the Glyph has decided to /// be involved with that location, the Glyph will need to return /// a valid Cursor. Otherwise, returning null will cause the /// the BehaviorService to simply ignore it. /// public override Cursor GetHitTest(Point p) { if (_bounds.Contains(p)) { return Cursors.Default; } return null; } ////// /// Overrides Glyph::Paint - this implementation does nothing. /// public override void Paint(PaintEventArgs pe) { } } ////// The transparent behavior on top of the DropDownGlyphs. /// internal class DropDownBehavior : ControlDesigner.TransparentBehavior { ////// /// Constructor that accepts the related ControlDesigner. /// private ToolStripMenuItemDesigner menuItemDesigner; internal DropDownBehavior(ControlDesigner designer, ToolStripMenuItemDesigner menuItemDesigner) : base(designer) { this.menuItemDesigner = menuItemDesigner; } ////// Drag drop support on the DropDown... /// public override void OnDragEnter(Glyph g, DragEventArgs e) { ToolStripItemDataObject data = e.Data as ToolStripItemDataObject; if (data != null) { e.Effect = (Control.ModifierKeys == Keys.Control) ? DragDropEffects.Copy : DragDropEffects.Move; } else { base.OnDragEnter(g, e); } } ////// Drag drop support on the DropDown... /// public override void OnDragOver(Glyph g, DragEventArgs e) { ToolStripItemDataObject data = e.Data as ToolStripItemDataObject; if (data != null) { e.Effect = (Control.ModifierKeys == Keys.Control) ? DragDropEffects.Copy : DragDropEffects.Move; } else { base.OnDragOver(g, e); } } ////// Drag drop support on the DropDown... /// [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")] public override void OnDragDrop(Glyph g, DragEventArgs e) { ToolStripItemDataObject data = e.Data as ToolStripItemDataObject; if (data != null) { ToolStripItem primaryItem = data.PrimarySelection; IDesignerHost host = (IDesignerHost)primaryItem.Site.GetService(typeof(IDesignerHost)); ToolStripDropDown parentToolStrip = primaryItem.GetCurrentParent() as ToolStripDropDown; ToolStripDropDownItem ownerItem = null; if (parentToolStrip != null) { ownerItem = parentToolStrip.OwnerItem as ToolStripDropDownItem; } Debug.Assert(ownerItem != null, "How can ownerItem be null for a menu item on a dropdown?"); if (ownerItem != null && host != null) { string transDesc; ArrayList components = data.DragComponents; int primaryIndex = -1; bool copy = (e.Effect == DragDropEffects.Copy); if (components.Count == 1) { string name = TypeDescriptor.GetComponentName(components[0]); if (name == null || name.Length == 0) { name = components[0].GetType().Name; } transDesc = SR.GetString(copy ? SR.BehaviorServiceCopyControl : SR.BehaviorServiceMoveControl, name); } else { transDesc = SR.GetString(copy ? SR.BehaviorServiceCopyControls : SR.BehaviorServiceMoveControls, components.Count); } // create a transaction so this happens as an atomic unit. DesignerTransaction changeParent = host.CreateTransaction(transDesc); try { IComponentChangeService changeSvc = (IComponentChangeService)primaryItem.Site.GetService(typeof(IComponentChangeService)); if (changeSvc != null) changeSvc.OnComponentChanging(ownerItem, TypeDescriptor.GetProperties(ownerItem)["DropDownItems"]); // If we are copying, then we want to make a copy of the components we are dragging if (copy) { // Remember the primary selection if we had one if (primaryItem != null) { primaryIndex = components.IndexOf(primaryItem); } ToolStripKeyboardHandlingService keyboardHandlingService = (ToolStripKeyboardHandlingService)primaryItem.Site.GetService(typeof(ToolStripKeyboardHandlingService)); if (keyboardHandlingService != null) { keyboardHandlingService.CopyInProgress = true; } components = DesignerUtils.CopyDragObjects(components, primaryItem.Site) as ArrayList; if (keyboardHandlingService != null) { keyboardHandlingService.CopyInProgress = false; } if (primaryIndex != -1) { primaryItem = components[primaryIndex] as ToolStripItem; } } if (e.Effect == DragDropEffects.Move || copy) { // Add the item. foreach (ToolStripItem toolItem in components) { parentToolStrip.Items.Add(toolItem); } // Open the DropDown for the PrimarySelection before the DRAG-DROP operation. ToolStripDropDownItem dropDownItem = primaryItem as ToolStripDropDownItem; if (dropDownItem != null) { ToolStripMenuItemDesigner dropDownItemDesigner = host.GetDesigner(dropDownItem) as ToolStripMenuItemDesigner; if (dropDownItemDesigner != null) { dropDownItemDesigner.InitializeDropDown(); } } //Set the Selection .. menuItemDesigner.selSvc.SetSelectedComponents(new IComponent[] { primaryItem }, SelectionTypes.Primary | SelectionTypes.Replace); } if (changeSvc != null) { changeSvc.OnComponentChanged(ownerItem, TypeDescriptor.GetProperties(ownerItem)["DropDownItems"], null, null); } //fire extra changing/changed events so that the order is "restored" after undo/redo if (copy) { if (changeSvc != null) { changeSvc.OnComponentChanging(ownerItem, TypeDescriptor.GetProperties(ownerItem)["DropDownItems"]); changeSvc.OnComponentChanged(ownerItem, TypeDescriptor.GetProperties(ownerItem)["DropDownItems"], null, null); } } //If Parent is DropDown... we have to manage the Glyphs .... if (ownerItem != null) { ToolStripMenuItemDesigner ownerDesigner = host.GetDesigner(ownerItem) as ToolStripMenuItemDesigner; if (ownerDesigner != null) { ownerDesigner.InitializeBodyGlyphsForItems(false, ownerItem); ownerDesigner.InitializeBodyGlyphsForItems(true, ownerItem); } } // Refresh the BehaviorService. BehaviorService bSvc = (BehaviorService)primaryItem.Site.GetService(typeof(BehaviorService)); if (bSvc != null) { bSvc.SyncSelection(); } } catch { if (changeParent != null) { changeParent.Cancel(); changeParent = null; } } finally { if (changeParent != null) changeParent.Commit(); changeParent = null; } } } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- URLIdentityPermission.cs
- CodeGenHelper.cs
- ActivityBindForm.cs
- XmlSchemaValidationException.cs
- BooleanStorage.cs
- DataIdProcessor.cs
- BitmapEffect.cs
- PeerNameRecord.cs
- ScrollBar.cs
- FormatException.cs
- DoubleCollection.cs
- DataGridViewTextBoxEditingControl.cs
- LinqDataSourceDeleteEventArgs.cs
- TextTrailingWordEllipsis.cs
- FieldToken.cs
- CompilerError.cs
- DnsEndPoint.cs
- SamlAuthorityBinding.cs
- COM2ExtendedTypeConverter.cs
- EntityClientCacheEntry.cs
- ActivityExecutorSurrogate.cs
- TableDetailsRow.cs
- TreeNodeCollection.cs
- List.cs
- AdapterUtil.cs
- DrawListViewColumnHeaderEventArgs.cs
- DataGridViewUtilities.cs
- ExpanderAutomationPeer.cs
- CodeChecksumPragma.cs
- XamlPoint3DCollectionSerializer.cs
- CheckedPointers.cs
- ParallelLoopState.cs
- StorageTypeMapping.cs
- ForeignKeyConstraint.cs
- MessageDecoder.cs
- ParentQuery.cs
- WindowsFont.cs
- ToolBarButton.cs
- CheckableControlBaseAdapter.cs
- Vector3DAnimation.cs
- XmlSerializerVersionAttribute.cs
- Exceptions.cs
- VirtualDirectoryMappingCollection.cs
- DataSourceCache.cs
- TraceContextEventArgs.cs
- MobileContainerDesigner.cs
- DictionaryItemsCollection.cs
- CustomAttributeSerializer.cs
- HandlerMappingMemo.cs
- CodeIterationStatement.cs
- ResourcePool.cs
- UIElement3D.cs
- RelationshipEntry.cs
- FastPropertyAccessor.cs
- LexicalChunk.cs
- Nullable.cs
- PropertyAccessVisitor.cs
- ComboBoxRenderer.cs
- ThreadStaticAttribute.cs
- UniqueEventHelper.cs
- DbParameterHelper.cs
- UrlAuthFailedErrorFormatter.cs
- D3DImage.cs
- XmlConvert.cs
- AuthenticationModuleElementCollection.cs
- SqlConnectionPoolProviderInfo.cs
- cookiecontainer.cs
- CodeTypeDeclaration.cs
- QueueException.cs
- SHA512Cng.cs
- DictionaryBase.cs
- LinkUtilities.cs
- CodeSnippetStatement.cs
- UDPClient.cs
- CustomCredentialPolicy.cs
- CodeArgumentReferenceExpression.cs
- Unit.cs
- RenderData.cs
- DataSysAttribute.cs
- EventLogPermissionAttribute.cs
- ConstantSlot.cs
- GPRECTF.cs
- SpellerInterop.cs
- PeerName.cs
- LinqDataSourceContextEventArgs.cs
- NullExtension.cs
- designeractionbehavior.cs
- OpenTypeCommon.cs
- PathBox.cs
- FixedSOMImage.cs
- EntityConnection.cs
- AvtEvent.cs
- SettingsBindableAttribute.cs
- PaintValueEventArgs.cs
- CodeEntryPointMethod.cs
- PageAsyncTaskManager.cs
- SystemInfo.cs
- BrowserPolicyValidator.cs
- ValueChangedEventManager.cs
- FileDataSourceCache.cs