danielreber

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,




Re: Windows Forms Designer Using IMenuCommandService

danielreber

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;

}






Re: Windows Forms Designer Using IMenuCommandService

Ken_Bussell

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





Re: Windows Forms Designer Using IMenuCommandService

danielreber

Thanks Ken, I sent you an email.




Re: Windows Forms Designer Using IMenuCommandService

Ken_Bussell

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





Re: Windows Forms Designer Using IMenuCommandService

Ken_Bussell

I said paste in my response but did a generic method. I hope you caught that. :)



Re: Windows Forms Designer Using IMenuCommandService

danielreber

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,

 






Re: Windows Forms Designer Using IMenuCommandService

danielreber

I also used a 'regular menu' on the form and that had the same results as the verbs.




Re: Windows Forms Designer Using IMenuCommandService

Ken_Bussell

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





Re: Windows Forms Designer Using IMenuCommandService

danielreber

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

Regards,






Re: Windows Forms Designer Using IMenuCommandService

danielreber

Ken,

Did you get a chance to complete your example

Thanks






Re: Windows Forms Designer Using IMenuCommandService

Ken_Bussell

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

}





Re: Windows Forms Designer Using IMenuCommandService

Ken_Bussell

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





Re: Windows Forms Designer Using IMenuCommandService

Matt

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




Re: Windows Forms Designer Using IMenuCommandService

Ken_Bussell

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 from UndoEngine

and keep track of everything. I would give you mine, but it isn't quite right and I don't want that code getting out there yet. If you google UndoEngine you 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