Discussion:
Custom Forms Designer Context Menus
(too old to reply)
David Whitchurch-Bennett
2006-05-03 13:33:07 UTC
Permalink
Hi,

Another question about Custom Forms Designers...

I would like to be able to add context menus to my controls, so if the user
clicks on any of the controls on the design surface, a popup menu appears. I
have tried to work with the MenuCommandService, and can add the verb and
handler, but cannot seem to get the menu to appear when right-clicking.

Thanks in advance!

David.
Linda Liu [MSFT]
2006-05-04 11:07:17 UTC
Permalink
Hi David,

Thank you for posting.

This is a quick note to let you know that I am performing research on this
issue and will get back to you as soon as possible. I appreciate your
patience.


Sincerely,
Linda Liu
Microsoft Online Community Support

====================================================
When responding to posts,please "Reply to Group" via
your newsreader so that others may learn and benefit
from your issue.
====================================================
G Himangi
2006-05-04 11:19:38 UTC
Permalink
You can specify context menu verbs for your controls by associating a
designer (derived from ControlDesigner) for your controls and overriding the
Verbs property of the designer class.

G Himangi, Sky Software
http://www.ssware.com
*Shell MegaPack for ActiveX & .Net : Advanced Controls for Drop-In Windows
Explorer GUI for your App.
*EZNamespaceExtensions.Net : Rapid Development of Shell Namespace Extensions
in .Net
*EZShellExtensions.Net : Rapid Development of IE Toolbars, IE Explorer Bars
& Windows Shell Extensions in .Net
Post by David Whitchurch-Bennett
Hi,
Another question about Custom Forms Designers...
I would like to be able to add context menus to my controls, so if the user
clicks on any of the controls on the design surface, a popup menu appears. I
have tried to work with the MenuCommandService, and can add the verb and
handler, but cannot seem to get the menu to appear when right-clicking.
Thanks in advance!
David.
InK_
2006-05-06 08:05:27 UTC
Permalink
Hi David

If you want to have different items for different controls you should implement your spesialized designer for your controls and override Verbs property.

I had a task to do 'Send to back' and 'Bring to front' as global verbs.

I did this in the following way:
1) implemented System.ComponentModel.Design.IMenuCommandService
2)added it to the custom designerhost which implemented IServiceContainer
serviceContainer.AddService(typeof(IMenuCommandService), new MenuCommandServiceImpl(this));

and then :
//add global verbs
IMenuCommandService menuCommandService = (IMenuCommandService)this.GetService(typeof(IMenuCommandService));
DesignerVerb verb = new DesignerVerb("Bring To Front", new EventHandler(this.BringToFrontClickHandler), StandardCommands.BringToFront);
menuCommandService.AddVerb(verb);
verb = new DesignerVerb("Send To Back", new EventHandler(this.SendToBackClickHandler), StandardCommands.SendToBack);
menuCommandService.AddVerb(verb);

3)Handlers
private void BringToFrontClickHandler(object sender, EventArgs e)
{
IMenuCommandService menuCommandService = (IMenuCommandService)this.GetService(typeof(IMenuCommandService));
menuCommandService.GlobalInvoke(StandardCommands.BringToFront);
}
private void SendToBackClickHandler(object sender, EventArgs e)
{
IMenuCommandService menuCommandService = (IMenuCommandService)this.GetService(typeof(IMenuCommandService));
menuCommandService.GlobalInvoke(StandardCommands.SendToBack);
}
4) then I should hide the context menu on selectionService_SelectedChanged
//hide opened context menu
MenuCommandServiceImpl menuService = (MenuCommandServiceImpl)m_host.GetService(typeof(IMenuCommandService));
menuService.HideContextMenu();
Hope it will help somehow.
--
Regards,
Inna Stetsyak aka InK_
Post by David Whitchurch-Bennett
Hi,
Another question about Custom Forms Designers...
I would like to be able to add context menus to my controls, so if the user
clicks on any of the controls on the design surface, a popup menu appears. I
have tried to work with the MenuCommandService, and can add the verb and
handler, but cannot seem to get the menu to appear when right-clicking.
Thanks in advance!
David.
Linda Liu [MSFT]
2006-05-08 07:10:52 UTC
Permalink
Hi David,

In order to get a menu to pop up when right-clicking on a custom design
surface, you should do two things. The first thing is to create a class
implementing the Interface IMenuCommandService and add the service to the
custom design surface. The second thing is to add verbs to the
MenuCommandService.

Suppose you have opened a form in the custom design surface and added
several controls on the form. When you right-click on the controls or the
form in your custom design surface, a context menu will appear.

If you want to have a different menu item when you right-click on a custom
control in your custom design surface, you should associate a designer to
your custom control and override the Verbs property of the designer class.

The following is a sample.
// the definition of a class implementing IMenuCommandService
public class MenuCommandServiceImpl : IMenuCommandService
{
// the host
private IDesignerHost host;
// commandId-command mapping
private IDictionary commands;
// menuItem-verb mapping
private IDictionary menuItemVerb;
// the global verbs collection.
private DesignerVerbCollection globalVerbs;
// we use the same context menu over-and-over
private ContextMenu contextMenu;
// we keep the lastSelectedComponent around
private IComponent lastSelectedComponent;

public MenuCommandServiceImpl(IDesignerHost host)
{
this.host = host;
commands = new Hashtable();
globalVerbs = new DesignerVerbCollection();
menuItemVerb = new Hashtable();
contextMenu = new ContextMenu();
lastSelectedComponent = null;
}
#region Implementation of IMenuCommandService

/// called to add a MenuCommand
public void AddCommand(System.ComponentModel.Design.MenuCommand
command)
{
if (command == null)
{
throw new ArgumentException("command");
}
// don't add commands twice
if (FindCommand(command.CommandID) == null)
{
commands.Add(command.CommandID, command);
}
}

/// called to remove a MenuCommand
public void RemoveCommand(System.ComponentModel.Design.MenuCommand
command)
{
if (command == null)
{
throw new ArgumentException("command");
}
commands.Remove(command.CommandID);
}

/// called when to add a global verb
public void AddVerb(System.ComponentModel.Design.DesignerVerb verb)
{
if (verb == null)
{
throw new ArgumentException("verb");
}
globalVerbs.Add(verb);
// create a menu item for the verb and add it to the context
menu
MenuItem menuItem = new MenuItem(verb.Text);
menuItem.Click += new EventHandler(MenuItemClickHandler);
menuItemVerb.Add(menuItem, verb);
contextMenu.MenuItems.Add(menuItem);
}
/// called to remove global verb
public void RemoveVerb(System.ComponentModel.Design.DesignerVerb
verb)
{
if (verb == null)
{
throw new ArgumentException("verb");
}

globalVerbs.Remove(verb);

// find the menu item associated with the verb
MenuItem associatedMenuItem = null;
foreach (DictionaryEntry de in menuItemVerb)
{
if (de.Value == verb)
{
associatedMenuItem = de.Key as MenuItem;
break;
}
}
// if we found the verb's menu item, remove it
if (associatedMenuItem != null)
{
menuItemVerb.Remove(associatedMenuItem);
}
// remove the verb from the context menu too
contextMenu.MenuItems.Remove(associatedMenuItem);
}
/// returns the MenuCommand associated with the commandId.
public System.ComponentModel.Design.MenuCommand
FindCommand(System.ComponentModel.Design.CommandID commandID)
{
return commands[commandID] as MenuCommand;
}

/// called to invoke a command
public bool GlobalInvoke(System.ComponentModel.Design.CommandID
commandID)
{
bool result = false;
MenuCommand command = FindCommand(commandID);
if (command != null)
{
command.Invoke();
result = true;
}
return result;
}

/// called to show the context menu for the selected component.
public void ShowContextMenu(System.ComponentModel.Design.CommandID
menuID, int x, int y)
{
ISelectionService selectionService =
host.GetService(typeof(ISelectionService)) as ISelectionService;
// get the primary component
IComponent primarySelection = selectionService.PrimarySelection
as IComponent;
// if the he clicked on the same component again then just show
the context
// menu. otherwise, we have to throw away the previous
// set of local menu items and create new ones for the newly
// selected component
if (lastSelectedComponent != primarySelection)
{
// remove all non-global menu items from the context menu
ResetContextMenu();
// get the designer
IDesigner designer = host.GetDesigner(primarySelection);
// not all controls need a desinger
if (designer != null)
{
// get designer's verbs
DesignerVerbCollection verbs = designer.Verbs;
foreach (DesignerVerb verb in verbs)
{
// add new menu items to the context menu
CreateAndAddLocalVerb(verb);
}
}
}
// we only show designer context menus for controls
if (primarySelection is Control)
{
Control comp = primarySelection as Control;
Point pt = comp.PointToScreen(new Point(0, 0));
contextMenu.Show(comp, new Point(x - pt.X, y - pt.Y));


}
// keep the selected component for next time
lastSelectedComponent = primarySelection;
}

/// returns the the current designer verbs
public System.ComponentModel.Design.DesignerVerbCollection Verbs
{
get
{
// create a new collection
DesignerVerbCollection availableVerbs = new
DesignerVerbCollection();
// add the global verbs
if (globalVerbs != null && globalVerbs.Count > 0)
{
availableVerbs.AddRange(globalVerbs);
}
// now add the local verbs
ISelectionService selectionService =
host.GetService(typeof(ISelectionService)) as ISelectionService;
IComponent primaryComponent =
selectionService.PrimarySelection as IComponent;
if (primaryComponent != null)
{
IDesigner designer = host.GetDesigner(primaryComponent);
if (designer != null && designer.Verbs != null &&
designer.Verbs.Count > 0)
{
availableVerbs.AddRange(designer.Verbs);
}
}
return availableVerbs;
}
}

#endregion

// called to invoke menu item verbs
private void MenuItemClickHandler(object sender, EventArgs e)
{
// get the menu item
MenuItem menuItem = sender as MenuItem;
if (menuItem != null)
{
// get and invoke the verb
DesignerVerb verb = menuItemVerb[menuItem] as DesignerVerb;
if (verb != null)
{
try
{
verb.Invoke();
}
catch { }
}
}
}
// removes all local verbs from the context menu
private void ResetContextMenu()
{
if (contextMenu != null && contextMenu.MenuItems != null &&
contextMenu.MenuItems.Count > 0)
{
MenuItem[] menuItemArray = new
MenuItem[contextMenu.MenuItems.Count];
contextMenu.MenuItems.CopyTo(menuItemArray, 0);
foreach (MenuItem menuItem in menuItemArray)
{
// if its not in the global list, remove it
if (!IsInGlobalList(menuItem.Text))
{
contextMenu.MenuItems.Remove(menuItem);
}
// get rid of the menu item from the mapping
menuItemVerb.Remove(menuItem);
}
}
}
// creats and adds a local verb
private void CreateAndAddLocalVerb(DesignerVerb verb)
{
if (verb == null)
{
throw new ArgumentException("verb");
}
VerifyVerb(verb);
// create a menu item for the verb
MenuItem menuItem = new MenuItem(verb.Text);
// attach the menu item click listener
menuItem.Click += new EventHandler(MenuItemClickHandler);
// do the menuItem-verb mapping
menuItemVerb.Add(menuItem, verb);
// add to context menu
contextMenu.MenuItems.Add(menuItem);
}
// returns true if the verb is in the global verb collection
private bool IsInGlobalList(string verbText)
{
bool found = false;
if (globalVerbs != null && globalVerbs.Count > 0)
{
foreach (DesignerVerb dv in globalVerbs)
{
if (string.Compare(dv.Text, verbText, true) == 0)
{
found = true;
break;
}
}
}
return found;
}
// we can't add the same verb twice
private void VerifyVerb(DesignerVerb verb)
{
if (verb == null)
{
throw new ArgumentException("verb");
}
// make sure the verb is not in the global list
if (globalVerbs != null && globalVerbs.Count > 0)
{
foreach (DesignerVerb dv in globalVerbs)
{
if (string.Compare(dv.Text, verb.Text, true) == 0)
{
throw new Exception("Cannot add the same verb
twice.");
}
}
}
// now check the menuItemVerb mapping
if (menuItemVerb != null && menuItemVerb.Count > 0)
{
foreach (DesignerVerb dv in menuItemVerb.Values)
{
if (string.Compare(dv.Text, verb.Text, true) == 0)
{
throw new Exception("Cannot add the same verb
twice.");
}
}
}
}

}

// add the MenuCommandService to the class HostSurface
public class HostSurface : DesignSurface
{
public HostSurface() : base()
{
IDesignerHost host = (IDesignerHost)this.GetService(typeof
IDesignerHost));
this.AddService(typeof(IMenuCommandService), new
MenuCommandServiceImpl(host));

// add verbs to the MenuCommandService in HostSurface class
IMenuCommandService _menucommandService =
(IMenuCommandService)this.GetService(typeof(IMenuCommandService));
DesignerVerb m_Verb = new DesignerVerb("First Designer
Verb", new EventHandler(OnFirstItemSelected));
_menucommandService.AddVerb(m_Verb);
m_Verb = new DesignerVerb("Second Designer Verb", new
EventHandler(OnSecondItemSelected));
_menucommandService.AddVerb(m_Verb);
}
private void OnFirstItemSelected(object sender, EventArgs args)
{
// Display a message
System.Windows.Forms.MessageBox.Show("The first designer verb
was invoked.");
}

private void OnSecondItemSelected(object sender, EventArgs args)
{
// Display a message
System.Windows.Forms.MessageBox.Show("The second designer verb
was invoked.");
}
}


Hope this is helpful to you.
If you have any other concerns or need anything else, please feel free to
let me know.


Sincerely,
Linda Liu
Microsoft Online Community Support

====================================================
When responding to posts,please "Reply to Group" via
your newsreader so that others may learn and benefit
from your issue.
====================================================
David Whitchurch-Bennett
2006-05-11 15:49:45 UTC
Permalink
Hi Linda,

Sorry for the delay - been a bit sidetracked with other projects...

Your code worked fantastically, so thanks for that. Converted the
implmentation to VB, so here it is in VB.Net for anyone else who may need
some help with this problem (outlook express put all the extra spacing in!)

David

Imports System.ComponentModel
Imports System.ComponentModel.Design

Public Class MenuCommandServiceImpl
Implements IMenuCommandService

' the host

Private host As IDesignerHost

' commandId-command mapping

Private commands As IDictionary

' menuItem-verb mapping

Private menuItemVerb As IDictionary

' the global verbs collection.

Private globalVerbs As DesignerVerbCollection

' we use the same context menu over-and-over

Private contextMenu As ContextMenu

' we keep the lastSelectedComponent around

Private lastSelectedComponent As IComponent

Public Sub New(ByVal host As IDesignerHost)

Me.host = host

commands = New Hashtable()

globalVerbs = New DesignerVerbCollection()

menuItemVerb = New Hashtable()

contextMenu = New ContextMenu()

lastSelectedComponent = Nothing

End Sub

#Region "Implementation of IMenuCommandService"

'/ called to add a MenuCommand

Public Sub AddCommand(ByVal command As
System.ComponentModel.Design.MenuCommand) Implements
IMenuCommandService.AddCommand

If command Is Nothing Then

Throw New ArgumentException("command")

End If

' don't add commands twice

If FindCommand(command.CommandID) Is Nothing Then

commands.Add(command.CommandID, command)

End If

End Sub

'/ called to remove a MenuCommand

Public Sub RemoveCommand(ByVal command As
System.ComponentModel.Design.MenuCommand) Implements
IMenuCommandService.RemoveCommand

If command Is Nothing Then

Throw New ArgumentException("command")

End If

commands.Remove(command.CommandID)

End Sub

'/ called when to add a global verb

Public Sub AddVerb(ByVal verb As System.ComponentModel.Design.DesignerVerb)
Implements IMenuCommandService.AddVerb

If verb Is Nothing Then

Throw New ArgumentException("verb")

End If

globalVerbs.Add(verb)

' create a menu item for the verb and add it to the context Menu

Dim menuItem As MenuItem = New MenuItem(verb.Text)

AddHandler menuItem.Click, AddressOf MenuItemClickHandler

menuItemVerb.Add(MenuItem, verb)

contextMenu.MenuItems.Add(MenuItem)

End Sub

'/ called to remove global verb

Public Sub RemoveVerb(ByVal verb As
System.ComponentModel.Design.DesignerVerb) Implements
IMenuCommandService.RemoveVerb

If verb Is Nothing Then

Throw New ArgumentException("verb")

End If

globalVerbs.Remove(verb)

' find the menu item associated with the verb

Dim associatedMenuItem As MenuItem = Nothing

Dim de As DictionaryEntry

For Each de In menuItemVerb

If de.Value Is verb Then

associatedMenuItem = de.Key

Exit For

End If

Next

' if we found the verb's menu item, remove it

If Not associatedMenuItem Is Nothing Then

menuItemVerb.Remove(associatedMenuItem)

End If

' remove the verb from the context menu too

contextMenu.MenuItems.Remove(associatedMenuItem)

End Sub

'/ returns the MenuCommand associated with the commandId.

Public Function FindCommand(ByVal commandID As CommandID) As MenuCommand
Implements IMenuCommandService.FindCommand

Return commands(commandID)

End Function

'/ called to invoke a command

Public Function GlobalInvoke(ByVal commandID As
System.ComponentModel.Design.CommandID) As Boolean Implements
IMenuCommandService.GlobalInvoke

Dim result As Boolean = False

Dim command As MenuCommand = FindCommand(commandID)

If Not command Is Nothing Then

command.Invoke()

result = True

End If

Return result

End Function

'/ called to show the context menu for the selected component.

Public Sub ShowContextMenu(ByVal menuID As
System.ComponentModel.Design.CommandID, ByVal x As Integer, ByVal y As
Integer) Implements IMenuCommandService.ShowContextMenu

Dim selectionService As ISelectionService =
host.GetService(GetType(ISelectionService))

' get the primary component

Dim primarySelection As IComponent = selectionService.PrimarySelection

' if the he clicked on the same component again then just show the(context)

' menu. otherwise, we have to throw away the previous

' set of local menu items and create new ones for the newly

' selected component

If lastSelectedComponent Is primarySelection Then

' remove all non-global menu items from the context menu

ResetContextMenu()

' get the designer

Dim designer As IDesigner = host.GetDesigner(primarySelection)

' not all controls need a desinger

If Not designer Is Nothing Then

' get designer's verbs

Dim verbs As DesignerVerbCollection = designer.Verbs

Dim verb As DesignerVerb

For Each verb In verbs

' add new menu items to the context menu

CreateAndAddLocalVerb(verb)

Next

End If

End If

' we only show designer context menus for controls

If TypeOf primarySelection Is Control Then

Dim comp As Control = primarySelection

Dim pt As Point = comp.PointToScreen(New Point(0, 0))

contextMenu.Show(comp, New Point(x - pt.X, y - pt.Y))

End If

' keep the selected component for next time

lastSelectedComponent = primarySelection

End Sub

'/ returns the the current designer verbs

Public ReadOnly Property Verbs() As
System.ComponentModel.Design.DesignerVerbCollection Implements
IMenuCommandService.Verbs

Get

' create a new collection

Dim availableVerbs As DesignerVerbCollection = New DesignerVerbCollection()

' add the global verbs

If globalVerbs Is Nothing Then

If globalVerbs.Count > 0 Then

availableVerbs.AddRange(globalVerbs)

End If

End If

' now add the local verbs

Dim selectionService As ISelectionService =
host.GetService(GetType(ISelectionService))

Dim primaryComponent As IComponent = selectionService.PrimarySelection

If Not primaryComponent Is Nothing Then

Dim designer As IDesigner = host.GetDesigner(primaryComponent)

If Not designer Is Nothing Then

If designer.Verbs Is Nothing Then

availableVerbs.AddRange(designer.Verbs)

End If

End If

End If

Return availableVerbs

End Get

End Property

#End Region

' called to invoke menu item verbs

Private Sub MenuItemClickHandler(ByVal sender As Object, ByVal e As
EventArgs)

' get the menu item

Dim menuItem As MenuItem = sender

If Not menuItem Is Nothing Then

' get and invoke the verb

Dim verb As DesignerVerb = menuItemVerb(menuItem)

If Not verb Is Nothing Then

Try

verb.Invoke()

Catch ex As Exception

' do nothing

End Try

End If

End If

End Sub

' removes all local verbs from the context menu

Private Sub ResetContextMenu()

If Not contextMenu Is Nothing Then

If contextMenu.MenuItems Is Nothing Then

Dim menuItemArray() As MenuItem = Nothing

contextMenu.MenuItems.CopyTo(menuItemArray, 0)

Dim menuItem As MenuItem

For Each menuItem In menuItemArray

' if its not in the global list, remove it

If Not IsInGlobalList(menuItem.Text) Then

contextMenu.MenuItems.Remove(menuItem)

End If

' get rid of the menu item from the mapping

menuItemVerb.Remove(menuItem)

Next

End If

End If

End Sub

' creats and adds a local verb

Private Sub CreateAndAddLocalVerb(ByVal verb As DesignerVerb)

If verb Is Nothing Then

Throw New ArgumentException("verb")

End If

VerifyVerb(verb)

' create a menu item for the verb

Dim menuItem As MenuItem = New MenuItem(verb.Text)

' attach the menu item click listener

AddHandler menuItem.Click, AddressOf MenuItemClickHandler

' do the menuItem-verb mapping

menuItemVerb.Add(MenuItem, verb)

' add to context menu

contextMenu.MenuItems.Add(MenuItem)

End Sub

' returns true if the verb is in the global verb collection

Private Function IsInGlobalList(ByVal verbText As String) As Boolean

Dim found As Boolean = False

If Not globalVerbs Is Nothing Then

If globalVerbs.Count > 0 Then

Dim dv As DesignerVerb

For Each dv In globalVerbs

If String.Compare(dv.Text, verbText, True) = 0 Then

found = True

Exit For

End If

Next

End If

End If

Return found

End Function

' we can't add the same verb twice

Private Sub VerifyVerb(ByVal verb As DesignerVerb)

If verb Is Nothing Then

Throw New ArgumentException("verb")

End If

' make sure the verb is not in the global list

If Not globalVerbs Is Nothing Then

If globalVerbs.Count > 0 Then

Dim dv As DesignerVerb

For Each dv In globalVerbs

If String.Compare(dv.Text, verb.Text, True) = 0 Then

Throw New Exception("Cannot add the same verb twice.")

End If

Next

End If

End If

' now check the menuItemVerb mapping

If Not menuItemVerb Is Nothing Then

If menuItemVerb.Count > 0 Then

Dim dv As DesignerVerb

For Each dv In menuItemVerb.Values

If String.Compare(dv.Text, verb.Text, True) = 0 Then

Throw New Exception("Cannot add the same verb twice.")

End If

Next

End If

End If

End Sub

End Class

'' add the MenuCommandService to the class HostSurface

Public Class HostSurface

Inherits DesignSurface

Public Sub New()

MyBase.New()

Dim host As IDesignerHost = Me.GetService(GetType(IDesignerHost))

host.AddService(GetType(IMenuCommandService), New
MenuCommandServiceImpl(host))

' add verbs to the MenuCommandService in HostSurface class

Dim menucommandService As IMenuCommandService =
GetService(GetType(IMenuCommandService))

Dim m_Verb As DesignerVerb = New DesignerVerb("First Designer Verb(",
AddressOf OnFirstItemSelected)

menucommandService.AddVerb(m_Verb)

m_Verb = New DesignerVerb("Second Designer Verb", AddressOf
OnSecondItemSelected)

menucommandService.AddVerb(m_Verb)

End Sub

Private Sub OnFirstItemSelected(ByVal sender As Object, ByVal arge As
EventArgs)

' Display a message

System.Windows.Forms.MessageBox.Show("The first designer verb was invoked.")

End Sub

Private Sub OnSecondItemSelected(ByVal sender As Object, ByVal args As
EventArgs)

' Display a message

System.Windows.Forms.MessageBox.Show("The second designer verb was
invoked.")

End Sub

End Class
Post by Linda Liu [MSFT]
Hi David,
In order to get a menu to pop up when right-clicking on a custom design
surface, you should do two things. The first thing is to create a class
implementing the Interface IMenuCommandService and add the service to the
custom design surface. The second thing is to add verbs to the
MenuCommandService.
Suppose you have opened a form in the custom design surface and added
several controls on the form. When you right-click on the controls or the
form in your custom design surface, a context menu will appear.
If you want to have a different menu item when you right-click on a custom
control in your custom design surface, you should associate a designer to
your custom control and override the Verbs property of the designer class.
The following is a sample.
// the definition of a class implementing IMenuCommandService
public class MenuCommandServiceImpl : IMenuCommandService
{
// the host
private IDesignerHost host;
// commandId-command mapping
private IDictionary commands;
// menuItem-verb mapping
private IDictionary menuItemVerb;
// the global verbs collection.
private DesignerVerbCollection globalVerbs;
// we use the same context menu over-and-over
private ContextMenu contextMenu;
// we keep the lastSelectedComponent around
private IComponent lastSelectedComponent;
public MenuCommandServiceImpl(IDesignerHost host)
{
this.host = host;
commands = new Hashtable();
globalVerbs = new DesignerVerbCollection();
menuItemVerb = new Hashtable();
contextMenu = new ContextMenu();
lastSelectedComponent = null;
}
#region Implementation of IMenuCommandService
/// called to add a MenuCommand
public void AddCommand(System.ComponentModel.Design.MenuCommand
command)
{
if (command == null)
{
throw new ArgumentException("command");
}
// don't add commands twice
if (FindCommand(command.CommandID) == null)
{
commands.Add(command.CommandID, command);
}
}
/// called to remove a MenuCommand
public void RemoveCommand(System.ComponentModel.Design.MenuCommand
command)
{
if (command == null)
{
throw new ArgumentException("command");
}
commands.Remove(command.CommandID);
}
/// called when to add a global verb
public void AddVerb(System.ComponentModel.Design.DesignerVerb verb)
{
if (verb == null)
{
throw new ArgumentException("verb");
}
globalVerbs.Add(verb);
// create a menu item for the verb and add it to the context
menu
MenuItem menuItem = new MenuItem(verb.Text);
menuItem.Click += new EventHandler(MenuItemClickHandler);
menuItemVerb.Add(menuItem, verb);
contextMenu.MenuItems.Add(menuItem);
}
/// called to remove global verb
public void RemoveVerb(System.ComponentModel.Design.DesignerVerb
verb)
{
if (verb == null)
{
throw new ArgumentException("verb");
}
globalVerbs.Remove(verb);
// find the menu item associated with the verb
MenuItem associatedMenuItem = null;
foreach (DictionaryEntry de in menuItemVerb)
{
if (de.Value == verb)
{
associatedMenuItem = de.Key as MenuItem;
break;
}
}
// if we found the verb's menu item, remove it
if (associatedMenuItem != null)
{
menuItemVerb.Remove(associatedMenuItem);
}
// remove the verb from the context menu too
contextMenu.MenuItems.Remove(associatedMenuItem);
}
/// returns the MenuCommand associated with the commandId.
public System.ComponentModel.Design.MenuCommand
FindCommand(System.ComponentModel.Design.CommandID commandID)
{
return commands[commandID] as MenuCommand;
}
/// called to invoke a command
public bool GlobalInvoke(System.ComponentModel.Design.CommandID
commandID)
{
bool result = false;
MenuCommand command = FindCommand(commandID);
if (command != null)
{
command.Invoke();
result = true;
}
return result;
}
/// called to show the context menu for the selected component.
public void ShowContextMenu(System.ComponentModel.Design.CommandID
menuID, int x, int y)
{
ISelectionService selectionService =
host.GetService(typeof(ISelectionService)) as ISelectionService;
// get the primary component
IComponent primarySelection = selectionService.PrimarySelection
as IComponent;
// if the he clicked on the same component again then just show
the context
// menu. otherwise, we have to throw away the previous
// set of local menu items and create new ones for the newly
// selected component
if (lastSelectedComponent != primarySelection)
{
// remove all non-global menu items from the context menu
ResetContextMenu();
// get the designer
IDesigner designer = host.GetDesigner(primarySelection);
// not all controls need a desinger
if (designer != null)
{
// get designer's verbs
DesignerVerbCollection verbs = designer.Verbs;
foreach (DesignerVerb verb in verbs)
{
// add new menu items to the context menu
CreateAndAddLocalVerb(verb);
}
}
}
// we only show designer context menus for controls
if (primarySelection is Control)
{
Control comp = primarySelection as Control;
Point pt = comp.PointToScreen(new Point(0, 0));
contextMenu.Show(comp, new Point(x - pt.X, y - pt.Y));
}
// keep the selected component for next time
lastSelectedComponent = primarySelection;
}
/// returns the the current designer verbs
public System.ComponentModel.Design.DesignerVerbCollection Verbs
{
get
{
// create a new collection
DesignerVerbCollection availableVerbs = new
DesignerVerbCollection();
// add the global verbs
if (globalVerbs != null && globalVerbs.Count > 0)
{
availableVerbs.AddRange(globalVerbs);
}
// now add the local verbs
ISelectionService selectionService =
host.GetService(typeof(ISelectionService)) as ISelectionService;
IComponent primaryComponent =
selectionService.PrimarySelection as IComponent;
if (primaryComponent != null)
{
IDesigner designer =
host.GetDesigner(primaryComponent);
if (designer != null && designer.Verbs != null &&
designer.Verbs.Count > 0)
{
availableVerbs.AddRange(designer.Verbs);
}
}
return availableVerbs;
}
}
#endregion
// called to invoke menu item verbs
private void MenuItemClickHandler(object sender, EventArgs e)
{
// get the menu item
MenuItem menuItem = sender as MenuItem;
if (menuItem != null)
{
// get and invoke the verb
DesignerVerb verb = menuItemVerb[menuItem] as DesignerVerb;
if (verb != null)
{
try
{
verb.Invoke();
}
catch { }
}
}
}
// removes all local verbs from the context menu
private void ResetContextMenu()
{
if (contextMenu != null && contextMenu.MenuItems != null &&
contextMenu.MenuItems.Count > 0)
{
MenuItem[] menuItemArray = new
MenuItem[contextMenu.MenuItems.Count];
contextMenu.MenuItems.CopyTo(menuItemArray, 0);
foreach (MenuItem menuItem in menuItemArray)
{
// if its not in the global list, remove it
if (!IsInGlobalList(menuItem.Text))
{
contextMenu.MenuItems.Remove(menuItem);
}
// get rid of the menu item from the mapping
menuItemVerb.Remove(menuItem);
}
}
}
// creats and adds a local verb
private void CreateAndAddLocalVerb(DesignerVerb verb)
{
if (verb == null)
{
throw new ArgumentException("verb");
}
VerifyVerb(verb);
// create a menu item for the verb
MenuItem menuItem = new MenuItem(verb.Text);
// attach the menu item click listener
menuItem.Click += new EventHandler(MenuItemClickHandler);
// do the menuItem-verb mapping
menuItemVerb.Add(menuItem, verb);
// add to context menu
contextMenu.MenuItems.Add(menuItem);
}
// returns true if the verb is in the global verb collection
private bool IsInGlobalList(string verbText)
{
bool found = false;
if (globalVerbs != null && globalVerbs.Count > 0)
{
foreach (DesignerVerb dv in globalVerbs)
{
if (string.Compare(dv.Text, verbText, true) == 0)
{
found = true;
break;
}
}
}
return found;
}
// we can't add the same verb twice
private void VerifyVerb(DesignerVerb verb)
{
if (verb == null)
{
throw new ArgumentException("verb");
}
// make sure the verb is not in the global list
if (globalVerbs != null && globalVerbs.Count > 0)
{
foreach (DesignerVerb dv in globalVerbs)
{
if (string.Compare(dv.Text, verb.Text, true) == 0)
{
throw new Exception("Cannot add the same verb
twice.");
}
}
}
// now check the menuItemVerb mapping
if (menuItemVerb != null && menuItemVerb.Count > 0)
{
foreach (DesignerVerb dv in menuItemVerb.Values)
{
if (string.Compare(dv.Text, verb.Text, true) == 0)
{
throw new Exception("Cannot add the same verb
twice.");
}
}
}
}
}
// add the MenuCommandService to the class HostSurface
public class HostSurface : DesignSurface
{
public HostSurface() : base()
{
IDesignerHost host = (IDesignerHost)this.GetService(typeof
IDesignerHost));
this.AddService(typeof(IMenuCommandService), new
MenuCommandServiceImpl(host));
// add verbs to the MenuCommandService in HostSurface class
IMenuCommandService _menucommandService =
(IMenuCommandService)this.GetService(typeof(IMenuCommandService));
DesignerVerb m_Verb = new DesignerVerb("First Designer
Verb", new EventHandler(OnFirstItemSelected));
_menucommandService.AddVerb(m_Verb);
m_Verb = new DesignerVerb("Second Designer Verb", new
EventHandler(OnSecondItemSelected));
_menucommandService.AddVerb(m_Verb);
}
private void OnFirstItemSelected(object sender, EventArgs args)
{
// Display a message
System.Windows.Forms.MessageBox.Show("The first designer verb
was invoked.");
}
private void OnSecondItemSelected(object sender, EventArgs args)
{
// Display a message
System.Windows.Forms.MessageBox.Show("The second designer verb
was invoked.");
}
}
Hope this is helpful to you.
If you have any other concerns or need anything else, please feel free to
let me know.
Sincerely,
Linda Liu
Microsoft Online Community Support
====================================================
When responding to posts,please "Reply to Group" via
your newsreader so that others may learn and benefit
from your issue.
====================================================
Linda Liu [MSFT]
2006-05-12 01:38:58 UTC
Permalink
Hi David,

Appreciate your update and response. I am glad to hear that the problem has
been fixed. And you are so warm-hearted to convert the implementation to VB.

If you have any other questions or concerns, please do not hesitate to
contact us. It's always our pleasure to be of assistance.

Have a nice day!


Sincerely,
Linda Liu
Microsoft Online Community Support

====================================================
When responding to posts,please "Reply to Group" via
your newsreader so that others may learn and benefit
from your issue.
====================================================
Mazhar
2009-09-05 08:05:11 UTC
Permalink
Hi, i am unable to view the complete C# code posted by you (Linda Liu).
Can you please post the full code again?

All i can see is up till:
/// returns the the current designer verbs
public System.ComponentModel.Design.DesignerVerbCollection Verbs
{

Rest of the code is missing.
Thanks,
Mazha

From http://www.developmentnow.com/g/32_2006_5_0_0_748411/Custom-Forms-Designer-Context-Menus.ht

Posted via DevelopmentNow.com Group
http://www.developmentnow.com/g/

Loading...