locked
How to override ViewCode command? RRS feed

  • Question

  • It is almost a week that I am trying to figure out how to override ViewCode command. I have tried different things without any success.

    What I have done is to add a UsedCommand element to UsedCommands in vsct file and added my command handler using IMenuCommandService.

    <UsedCommands>
      <UsedCommand guid="guidVSStd97" id="cmdidViewCode" />    
    </UsedCommands>

    var viewCodeCommand = new OleMenuCommand(viewCodeCommand_Run, StandardCommands.ViewCode);
    viewCodeCommand.BeforeQueryStatus += new EventHandler(viewCodeCommand_BeforeQueryStatus);
    mcs.AddCommand(viewCodeCommand);

    This is exactly what has been suggested in lots of blogs and samples over the internet. What else is required?

    • Changed type SamNaseri Monday, December 24, 2012 5:59 AM
    Tuesday, December 18, 2012 6:38 AM

Answers

  • You can certainly handle it, look into IVsRegisterPriorityCommandTarget and know that both your package and your package's instance of IMenuCommanService both implement IOleCommandTarget.

    Ryan

    • Marked as answer by SamNaseri Monday, December 24, 2012 6:00 AM
    Tuesday, December 18, 2012 3:39 PM

All replies

  • I don't know who suggested a UsedCommand tag, but tat has nothing to do with command routing. We also never route commands to package level handlers if that package isn't the one that declared the command, in your case you did not, the shell did. What are you trying to do exactly? I can't imagine a scenario where overriding ViewCode at the package, or even window level would be the right approach.

    Ryan

    Tuesday, December 18, 2012 7:10 AM
  • So you mean it is not possible to handle ViewCode?

    In WPF, XAML files could exist without a companion code-behind file, and actually in most of my projects this is the case. So for me the 'View Code' actually has nothing to do. What I want to do is to open the ViewModel related to that Xaml file when I press F7 or use 'View Code' menu.

    I have already done the part in which I can find and open the View Model for active document. And at the moment it is using a separate Command for it.

    Tuesday, December 18, 2012 7:54 AM
  • You can certainly handle it, look into IVsRegisterPriorityCommandTarget and know that both your package and your package's instance of IMenuCommanService both implement IOleCommandTarget.

    Ryan

    • Marked as answer by SamNaseri Monday, December 24, 2012 6:00 AM
    Tuesday, December 18, 2012 3:39 PM
  • Thanks Ryan,

    Based on what you suggested now I am able to handle the View Code command. However still there is some problems.

    1. Only 'Context Menu->View Code' and 'View->Code' menus are working and the F7(key binding) is not working.

    2. When there is no code behind(The XAML file is standalone) then the View Code menu is not there and my command implementation is not invoked when pressing F7.

    I guess I have not done all you said. What do you mean by 'package's instance of IMenuCommonService'? Shall I implement that interface and register my implementation via IServiceContainer?

    Wednesday, December 19, 2012 1:12 AM
  • When you call GetService to get IMenuCommandService you get an instance that is unique to your toolwindow or package, it is not a shared service like say IVsRegisterPriorityCommandTarget, I was suggesting you use that instance as the argument to IVsRegisterPriorityCommandTarget::RegisterPriorityCommandTarget.

    What is your QueryStatus doing? If you want the command to be enabled you need to enable it and say it is supported. If the keybinding is not firing it is likely because the command is not enabled. How are you ensuring your package is loaded? We don't load packages just to perform QueryStatus.

    Ryan

    Wednesday, December 19, 2012 3:51 PM
  • Thank you again.

    By passing the instance of my IMenuCommandService to  IVsRegisterPriorityCommandTarget::RegisterPriorityCommandTarget now It is working well.

    The key binding problem was because I had a wrong assumption. ViewCode keybindings are not for global(I guess some sort of scope). The relevant command for F7 key which is handling this key in XAML editor is View.ToggleDesigner and by handling this command everything works as I expect.

    Although registering the IMenuCommandService solved my problem. I still am curious to know if Package implemented IOleCommandTarget how can I handle commands using that implementation? What I did was to implement the IOleCommandTarget once again in my own package class and this was my QueryStatus implementation which failed to work:

    publicint QueryStatus(refGuid pguidCmdGroup, uint cCmds, OLECMD[] prgCmds, IntPtr pCmdText) {     if (pguidCmdGroup == StandardCommands.ViewCode.Guid) {         foreach (var cmd in prgCmds) {             var current = cmd;             if (cmd.cmdID == StandardCommands.ViewCode.ID) {                 current.cmdf = OLECMDF.OLECMDF_SUPPORTED | OLECMDF.OLECMDF_ENABLED;                 returnVSConstants.S_OK;             }         }     }     return (int)Microsoft.VisualStudio.OLE.Interop.Constants.OLECMDERR_E_NOTSUPPORTED; }

       
    Thursday, December 20, 2012 12:43 AM
  • Did you register your package with IVsRegisterPriorityCommandTarget after doing this?

    The default implementation of Package.IOleCommandTarget (it implements it explicitly, which is annoying), simply fetches the IMenuCommandService, casts it to IOleCommandTarget and forwards to it. The IMenuCommandService's IOleCommandTarget simply looks for a registered Command object (it is just a dictionary that maps GUID/DWORD pairs -> Command objects) and if it finds one answers the QueryStatus by reading the properties off the Command object (like Enabled, Visible, etc..), possibly calling any BeforeQueryStatus handlers that exist before doing so. It then translates those bool values into OLEMCDF_ values to return to the caller (the shell).

    Assuming StandardCommands.ViewCode.Guid is the right GUID (where did you get that? Did you define it locally? I believe you want VSConstants.CMDSETID.StandardCommandSet97_guid and VSConstants.VSStd97CmdID.ViewCode) then what you have above looks right and should work, assuming you registered your package with IVsRegisterPriorityCommandTarget instead of registered the IMenuCommandService.

    Ryan

    Thursday, December 20, 2012 1:26 AM