3

I've got a report form designer written long ago for a database project. It used a lot of winapi magic hence i was forced to rewrite some parts 'in proper way'.

Thanks to some articles from MSDN magazine (here and here) and CodeProject i was able to implement designer surface, toolbox and undo/redo engine.

  1. Every resource i discovered on the topic so far is a bit outdated. Can you point to fresh/comprehensive article?

  2. Code from article mentioned above seems not working.

    MenuCommandService.ShowContextMenu is called but nothing appears since there aren't any DesignerVerbs in globalVerbs collection. Should i add 'standard' ones, corresponded to designer actions such as cut/paste, manually? If yes, how can i accomplish this?

Jon Seigel
  • 12,251
  • 8
  • 58
  • 92
jonny
  • 1,326
  • 9
  • 44
  • 62
  • 1
    I've never seen any good documentation in this area. Info on creating designers for controls, yes, but not for the whole form. I suggest you spend time looking at the source with Reflector, or else the shared source. – John Saunders May 20 '09 at 16:13

2 Answers2

3

Thanks to SharpDevelop sources i was able to figure out the solution

This minimal implementation (some standart commands, no more) worked for me

using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Diagnostics;
using System.Windows.Forms;
using System.Drawing;

namespace DesignerHost
{
    class MenuCommandServiceImpl : MenuCommandService
    {
        DesignerVerbCollection m_globalVerbs = new DesignerVerbCollection();

        public MenuCommandServiceImpl(IServiceProvider serviceProvider)
            : base(serviceProvider)
        {
            m_globalVerbs.Add(StandartVerb("Cut", StandardCommands.Cut));
            m_globalVerbs.Add(StandartVerb("Copy", StandardCommands.Copy));
            m_globalVerbs.Add(StandartVerb("Paste", StandardCommands.Paste));
            m_globalVerbs.Add(StandartVerb("Delete", StandardCommands.Delete));
            m_globalVerbs.Add(StandartVerb("Select All", StandardCommands.SelectAll));

        }

        private DesignerVerb StandartVerb(string text, CommandID commandID)
        {
            return new DesignerVerb(text,
                delegate(object o, EventArgs e) 
                {
                    IMenuCommandService ms = 
                        GetService(typeof(IMenuCommandService)) as IMenuCommandService;
                    Debug.Assert(ms != null);
                    ms.GlobalInvoke(commandID); 
                }
            );
        }

        class MenuItem : ToolStripMenuItem
        {
            DesignerVerb verb;

            public MenuItem(DesignerVerb verb)
                : base(verb.Text)
            {
                Enabled = verb.Enabled;
                this.verb = verb;
                Click += InvokeCommand;
            }

            void InvokeCommand(object sender, EventArgs e)
            {
                try
                {
                    verb.Invoke();
                }
                catch (Exception ex)
                {
                    Trace.Write("MenuCommandServiceImpl: " + ex.ToString());
                }
            }
        }

        private ToolStripItem[] BuildMenuItems()
        {
            List<ToolStripItem> items = new List<ToolStripItem>();

            foreach (DesignerVerb verb in m_globalVerbs) 
            {
                items.Add(new MenuItem(verb));
            }
            return items.ToArray();
        }

        #region IMenuCommandService Members

        /// This is called whenever the user right-clicks on a designer.
        public override void ShowContextMenu(CommandID menuID, int x, int y)
        {
            // Display our ContextMenu! Note that the coordinate parameters to this method
            // are in screen coordinates, so we've got to translate them into client coordinates.

            ContextMenuStrip cm = new ContextMenuStrip();
            cm.Items.AddRange(BuildMenuItems());

            ISelectionService ss = GetService(typeof (ISelectionService)) as ISelectionService;
            Debug.Assert(ss != null);

            Control ps = ss.PrimarySelection as Control;
            Debug.Assert(ps != null);

            Point s = ps.PointToScreen(new Point(0, 0));
            cm.Show(ps, new Point(x - s.X, y - s.Y));
        }

        #endregion

    }
}

Update

found similar solution

jonny
  • 1,326
  • 9
  • 44
  • 62
  • 1
    I know is late but in the "similar solution" there is a problem. There, if you click on a menu, it calls the verb using GlobalInvoke(designerVerb.CommandID). There are verbs that share the same CommandID (i.e. Add and Remove Tab from a TabStrip so the similar solution does not work in every condition. Here, on a menu click, the action to perform is called using designerVerb.Invoke() that works fine. – bubi Oct 06 '15 at 07:39
1

I ran into same problem a month ago and got something really intersting and helpful from CodePlex here. I read about this on Brad Abram's Blog Post. These includes many examples on framework extensibility and Custom Windows Form Designer Interface is one of them.

Link Txt 1: http://mef.codeplex.com/

Link Txt 2: http://blogs.msdn.com/brada/archive/2009/04/13/managed-extensibility-framework-preview-5-released.aspx

Thanks.

this. __curious_geek
  • 42,787
  • 22
  • 113
  • 137
  • There is no working design surface context menu here Apparently MEF studio designer is based on this MSDN code http://msdn.microsoft.com/en-us/magazine/cc163634.aspx – jonny May 26 '09 at 16:28