Windows Develop Bookmark and Share   
 index > Windows Forms Designer > Using IMenuCommandService
 

Using IMenuCommandService

I have application that is using IDesignerHost so my users can design dashboards at runtime. I got the IDesignerHost and INameCreationService, ISelectionService and IUIService services implemented and working but I cannot get IMenuCommandService implemented besides 'Delete'. I have found examples but it looks like they are all for component integration in the IDE. Does anybody know of some examples for my scenario?


Regards,

danielreber  Monday, March 05, 2007 3:17 PM

After more research I was able to supply a context menu using a 3rd party toolbar control and by overriding ShowContextMenu but

GlobalInvoke(StandardCommands.Delete) <-- see below

is still the only StandardCommands that works. In GlobalInvoke the line, command.Invoke(); is being executed for all StandardCommands that are passed in but nothing happens except for StandardCommands.Delete. Any ideas?

Regards,

Dan Reber

public bool GlobalInvoke(System.ComponentModel.Design.CommandID commandID)
{

bool result = false;

MenuCommand command = FindCommand(commandID);

if (command != null)
{
command.Invoke();
result = true;
}

return result;

}

danielreber  Monday, March 05, 2007 7:12 PM

Hello Dan,

>>After more research I was able to supply a context menu using a 3rd party toolbar control and by overriding ShowContextMenu but

You don't need to do this. The menucommand service when implemented correctly should do it for you.

I'm working on a sample for this right now, but I can probably get you started. Send me an e-mail and I'll get you some code.

Ken

Ken_Bussell  Monday, March 05, 2007 10:24 PM
Thanks Ken, I sent you an email.
danielreber  Monday, March 05, 2007 10:40 PM

Your class looks ok, but you should switch back to using a standard ContextMenu so your app isn't dependent on that third party control.

There are only a couple of differences between mine and yours. First I keep track of where the menu is for internal reasons.

I added my Undo and redo commands in the constructor

AddCommand(new MenuCommand(new EventHandler(this.ExecuteUndo), StandardCommands.Undo));

AddCommand(new MenuCommand(new EventHandler(this.ExecuteRedo), StandardCommands.Redo));

Then added the handlers

void ExecuteUndo(object sender, EventArgs e)

{

UndoEngineImpl undoEngine = _host.GetService(typeof(UndoEngine)) as UndoEngineImpl;

if (undoEngine != null)

undoEngine.DoUndo();

}

void ExecuteRedo(object sender, EventArgs e)

{

UndoEngineImpl undoEngine = _host.GetService(typeof(UndoEngine)) as UndoEngineImpl;

if (undoEngine != null)

undoEngine.DoRedo();

}

Other than that they are pretty close to the same except for a special addVerbs method that I have. So I don't think the problem is with your class.

Where did you add the designer verbs and what did you add (or did you even do this) ;)

What I mean is that if you want do to a Paste for example you would need to call

{YourMenuServiceImplementation}.AddVerb(_YourSpecialVerb);

Where _YourSpecialVerb is something like

DesignerVerb _YourSpecialVerb =new DesignerVerb("Exec My Function", new EventHandler(MyFunction));

And your event handler woudl be

public void MyFunction(object sender, EventArgs e)

{

//your implementation here

}

You could put something like

_MyMenuService.GlobalInvoke(StandardCommands.AlignRight):

or any of the StandardCommands inside the method.

The point is that the commands are ready to be used, but you need to do the implementation by adding Verbs I'm betting. If you've done this let me know and we'll go on. Once you add verbs, you will see new menu choices popping up. :)

Ken

Ken_Bussell  Monday, March 05, 2007 11:14 PM
I said paste in my response but did a generic method. I hope you caught that. :)
Ken_Bussell  Tuesday, March 06, 2007 12:50 PM

Ken,

I tried with verbs for Cut, Paste and ShowGrid but they do not work.  However, I added some for Align Top, Delete, and Send To Back and they did work.  I also sent you a test project.  So it seems that some work and some do not.  Do I need to do more than

GlobalInvoke(StandardCommands.Cut)

for the StandardCommands that are not working?

Regards,

 

danielreber  Tuesday, March 06, 2007 2:02 PM
I also used a 'regular menu' on the form and that had the same results as the verbs.
danielreber  Tuesday, March 06, 2007 2:23 PM

Dan,

At first I thought you get copy and paste for free, but now I'm thinking not. I went through my code and for some reason I'm handling the copy and paste functionality by keeping track of the objects copied with an internal array list. My environment is weird (I'm doing some strange things) but I'm not sure if it is because I couldn't get copy and paste working or because of my own internal reasons. It has been a while since I did this and my memory isn't all there.

I'm working on a good sample for this, but haven't gotten there yet. Let me see if I can get to the menu service today and see. However, when a friend of mine gets back from vacation, I can definately get you a good answer. It won't be until next week though. Maybe somebody out there knows if copy and paste is/supposed to be handled by the design environment or if you have to do it yourself?

Ken

Ken_Bussell  Tuesday, March 06, 2007 3:02 PM

Next week is fine but don't rush because I will be travling then. Thanks for your help Ken.

Regards,

danielreber  Tuesday, March 06, 2007 5:03 PM
Ken,

Did you get a chance to complete your example?

Thanks

danielreber  Monday, April 02, 2007 8:51 PM

Ok, Sorry about the delay Daniel. I was right that I have some strange things going on in my environment, but I went back to the essentials to get this to you.

I can't find the original forum post on this from Martin Thorsen, but in order to get copy and paste working you need to implement the IDesignerSerializationService Below is my implementation which is pretty basic, and pretty much the default version for any samples that you might find that have it. Understand that I didn't just figure this out or read it somewhere, I had to get some help. I say this because it is important to know that there isn't some secret place all the valuable information is hidden that only a few of us know about. We're all as lost as you are most of the time. These forums have so far been the best resource that I've found, mostly because the Microsoft gurus hang out here.

Just add this class to your project and then be sure to add the service.

//this ads the service to my host surface which is DesignSurface

this.AddService(typeof(IDesignerSerializationService), new DesignerSerializationService(serviceContainer));

then just do a

.GlobalInvoke(StandardCommands.Copy);

On your IMenuCommandService implementation and you've got copy and paste.

class DesignerSerializationService : IDesignerSerializationService

{

IServiceProvider serviceProvider;

public DesignerSerializationService(IServiceProvider serviceProvider)

{

this.serviceProvider = serviceProvider;

}

#region IDesignerSerializationService Members

public System.Collections.ICollection Deserialize(object serializationData)

{

SerializationStore serializationStore = serializationData as SerializationStore;

if (serializationStore != null)

{

ComponentSerializationService componentSerializationService = serviceProvider.GetService(typeof(ComponentSerializationService)) as ComponentSerializationService;

ICollection collection = componentSerializationService.Deserialize(serializationStore);

return collection;

}

return new object[0];

}

public object Serialize(System.Collections.ICollection objects)

{

ComponentSerializationService componentSerializationService = serviceProvider.GetService(typeof(ComponentSerializationService)) as ComponentSerializationService;

SerializationStore returnObject = null;

using (SerializationStore serializationStore = componentSerializationService.CreateStore())

{

foreach (object obj in objects)

{

if (obj is Control)

{

componentSerializationService.Serialize(serializationStore, obj);

}

}

returnObject = serializationStore;

}

return returnObject;

}

#endregion

}

Ken_Bussell  Tuesday, April 03, 2007 11:01 PM

Update: I've been working with Daniel some on this offline and there is a small problem. He is using the 1.1 framework designer, and not the 2.0. So he gets an exception when he tries to get the ComponentSerializationService in the Serialize and Deserialize methods above because he doesn't have the ComponentSerializationService added.

The code should check to make sure that it actually has the service before it tries to do something with it. My bad.

Ken

Ken_Bussell  Wednesday, April 04, 2007 9:46 PM
Hi Ken,

I am having the same problem. I have a DesignSurface in .NET 2.0 that I am trying to implement undo/redo and cut, copy, and paste in. Is it possible for you to send me the same examples that you send the other user? I tried adding the IDesignerSerializationService service, but I get an exception that the service already exists, so I tried removing it first then adding it. That did not work.

Thanks,
Matt
Matt5329535  Tuesday, April 10, 2007 11:16 PM

Hello Matt,

I posted the code for the serialization service in my code above. That is all I sent him. Once you implement that, you should have copy and paste if you call the propery StandardCommand. If you can't add the service, because it has already been added, that should be good enough. Don't remove a service if it has already been added, because you could cause another section of code to have problems.

I'm thinking that you are trying to add the service too late. Add it as soon as you possibly can before you do anything else. I add all of my services in the constructor of my design surface class. I've also found in some cases that the order you add the services can matter. For example,if you try to add a service that needs the DesignerSerializationService and it isn't there, it will add it, and your implementation will not be there. You see?

I add my services in the following order. In some cases it matters in others it doesn't. So this isn't the "right" way, just the way that is working for me.

DesignerOptionService

INameCreationService

IMenuCommandService

ComponentSerializationService

IDesignerSerializationService

UndoEngine

IToolboxService

Undo and Redo you do NOT get for free, meaning you can't just call StandardCommands.Undo. You have to derive a class fromUndoEngine

and keep track of everything.Iwould give you mine, but it isn't quite right and I don't want that code getting out there yet. If you google UndoEngineyou will eventually find a sample of how to implement an undo engine.You will have to add the service, but you shouldn't have too many problems. My first undo engine worked fine and it was from a sample.

Ken

Ken_Bussell  Wednesday, April 11, 2007 12:54 AM
Thanks Ken! That did the trick.
Matt5329535  Thursday, April 12, 2007 11:42 PM

i need help regarding ComponentSerializationService... how can i add this???

do i have to write implementation of this as well??

raoFFF  Sunday, May 27, 2007 5:35 PM

You only need to do your own implementation if you want to do something special.

this.AddService(typeof(ComponentSerializationService), new CodeDomComponentSerializationService(serviceContainer));

this = DesignSurface

Ken_Bussell  Tuesday, May 29, 2007 6:22 PM

hello : i am kmlgdx ,i could not get a content menu when a right click a button or label

and so on after i drag it to a designTime form ,how can i do ?

could you give some help or code ,thank you very much!

龙在天涯  Wednesday, September 03, 2008 3:49 AM

Hello,

Here are the basic steps.

1. Add the menu command service to your app

_mcsi = new MenuCommandServiceImpl();

_mcsi.SetHost(host);

host.AddService(typeof(IMenuCommandService), _mcsi);

the MenuCommandServiceImpl would be your implemenation of a class derived from IMenuCommandService

2. Create a DesignerVerb of some type to do something

DesignerVerb _SelectAllVerb = null;

_SelectAllVerb = new DesignerVerb("Select All", new EventHandler(SelectAll));

along with the event handler In this case select all.

private void SelectAll(object sender, EventArgs e)

{

_mnucommand.GlobalInvoke(StandardCommands.SelectAll);

}

To ge the verb to show up you have to use the ISelectionService.SelectionChanged event or something to give you an event that tells you when you want to add the trigger. For example I add the select all verb when the root component is selected.

then you jsut call the AddVerb command on your IMenuCommandService implementation.

mcsi.AddVerb(_SelectAllVerb, null);

I don't have any code to post that does all of this because it is not trivial to get it all working. If you want some additional help let me know.

Ken

Ken_Bussell  Wednesday, September 03, 2008 4:43 PM

oh,thanks ,i will try it !

龙在天涯  Thursday, September 04, 2008 1:32 AM

I want to do the Cut copy paste operation in the designer host..

hostingServiceContainer.AddService(typeof(IDesignerSerializationService), new DesignerSerializationService(

host as IServiceProvider));

mcs.GlobalInvoke(StandardCommands.Copy);

After that i added the DesignerSerializationService class in the IMenuCommandService implementation

I am getting an error "Object reference not set to an instance of an object." in the Serialize method

using (SerializationStore serializationStore = componentSerializationService.CreateStore())

Can you help me to solve this issue

Thanks

Sanbal  Saturday, November 29, 2008 7:21 AM
You need to addComponentSerializationService to the service container.

//------------------------------------------------------------------------------------------
CodeDomComponentSerializationService
codeDomComponentSerializationService =

new CodeDomComponentSerializationService(this.serviceContainer);

if (codeDomComponentSerializationService != null)

{

this.serviceContainer.RemoveService(typeof(ComponentSerializationService), false);

this.serviceContainer.AddService(typeof(ComponentSerializationService), codeDomComponentSerializationService);

}
//------------------------------------------------------------------------------------------

mazmoiz  Monday, December 15, 2008 2:09 PM
Hi,

I am using the StandardCommands: ShowGrid and SnapToGrid, among many others. However these two stopped working after converting my project from .NET 1.1 to 2.0.

Are there any changes between these two frameworks regarding this or am I missing something? Don't understand why it doesn't work.

IServiceContainersc1=host1asIServiceContainer;
IMenuCommandServicemcs1=sc1.GetService(typeof(IMenuCommandService))asIMenuCommandService;
mcs1.GlobalInvoke(StandardCommands.ShowGrid);


I don't get any exception or anything else, it just don't work!

Any help would be appreciated. Thanks

YusufB  Friday, February 06, 2009 1:08 PM

You can use google to search for other answers

Custom Search

More Threads

• Controls position on window resizings...
• Image Resizing in Compact Framework
• C# Active Directory Contact List
• IExtenderProvider and Design Time Attributes
• Programatically setting the column widths in a TableLayoutPanel.
• Create a designable base control? / Code generation for subclassed controls
• Custom Controls Question
• Form_resize does not fire?
• datagridview combobox
• do not allow change of text or deletion of a checkbox control