VSIX窗口-执行ICommand的关键快捷方式 [英] VSIX window - key shortcut to execute ICommand

查看:129
本文介绍了VSIX窗口-执行ICommand的关键快捷方式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

具有一个Visual Studio扩展(VSIX)项目:在 Window 中,我们获得了 UserControl ,其中将 Button 绑定到某些 ICommand.这完全可以按预期工作,但是我想附加一个快捷键(例如: CTRL + S ),该快捷方式将触发相同的 Command .

我检查了几个问题,发现其中最有用的这段代码:

 < UserControl.InputBindings>< KeyBinding修饰符="Ctrl" Key ="Esc" Command ="{Binding SaveCmd}"/></UserControl.InputBindings> 

然而,从未从按键中触发 Command ,我认为问题可能是:

    上面的
  • 代码不起作用?(我找到了一篇文章,其中应该使用 DependencyProperty 绑定到 Command
  • 按键被Visual Studio本身捕获( CTRL + S 正在保存文件)
  • 我可能需要在封装了 UserControl
  • Window 上设置绑定
  • 我可能需要在 * Package.vsct 中设置绑定,并通过它进行路由,因为这将成为Visual Studio中的 Command .

问题:我应该如何绑定到快捷键?我应该在哪里放置绑定?

解决方案

KeyBindings 似乎很复杂,需要在几个步骤上进行定义(也取决于要求).此答案是对 user1892538 的回答的补充.

场景::我们已经显示了toolWindow,但是我们想添加一些命令,该命令将在view/view-model中调用方法.


1.在Command (步骤3 )rel ="nofollow noreferrer">本教程):

右键单击项目->添加新项-> 自定义命令.这将创建2个文件,并使用以下软件包修改文件:

  • CommandName.png -菜单的图标
  • CommandName.cs -类文件,包括命令的源代码
  • ProjectWindowPackage.cs -带有 Initialize()方法的包装类,该方法调用 Initialize() CommandName.cs

MyWindowPackage.cs :

 公共密封类MyWindowPackage:包{公共常量字符串PackageGuidString ="00000000-0000-0000-0000-000000000003";公共MyWindowPackage(){}受保护的重写void Initialize(){MyToolWindowCommand.Initialize(this);MySaveCommand.Initialize(this);base.Initialize();}} 

CommandName.cs :

 //这两个值将进行绑定公共静态只读Guid ApplicationCommands= new Guid("00000000-0000-0000-0000-000000000002");public const int SaveCommandId = 0x0201;私有只读Package软件包;私有CommandName(打包软件包){//我们需要有一个包(来自Initialize()方法)来设置VS如果(package == null)抛出新的ArgumentNullException("package");this.package =包;//这提供了对菜单的访问(因此我们可以在初始化期间添加命令)OleMenuCommandService commandService = this.ServiceProvider.GetService(typeof(IMenuCommandService))as OleMenuCommandService;如果(commandService!= null){//创建新命令引用"(全局ID)var menuCommandID =新的CommandID(ApplicationCommands,SaveCommandId);//创建新的命令实例(调用方法,命令ID)var menuItem = new MenuCommand(this.Save,menuCommandID);//向菜单添加新命令commandService.AddCommand(menuItem);}私人void Save(){//获取我们的窗口对象的实例(参数false->不会创建新窗口)ToolWindowPane lToolWindow = this.package.FindToolWindow(typeof(MyToolWindow),0,false);如果((null == lToolWindow)||(null == lToolWindow.Frame))返回;//将toolWindow的内容作为Window处理(我们的控件)((lToolWindow as MyToolWindow)?. Content as MyWindowControl)?. Save();}} 


2.将MyToolWindow的内容设置为MyWindowControl(在创建VSIX时完成):

MyToolWindow.cs :

  [Guid("00000000-0000-0000-0000-000000000001")]//ToolWindow的GUID公共类MyToolWindow:ToolWindowPane{公共MyToolWindow():base(null){this.Content = new MyWindowControl();}} 


3.在后台代码中设置代码以调用ViewModel(或自行完成工作):

MyWindowControl.cs :

 公共子类MyWindowControl:UserControl{//为简洁起见,省略了输出公共无效Save(){//对视图模型进行调用或运行代码(this.DataContext作为MyViewModel)?. SaveCmd.Execute(null);}} 


4.使用 Shortcut 设置 Command ,以便VS知道如何处理它们:

MZTools的文章中可以找到解决方案如何添加 Command 而不在菜单中看到它,但是如果您要转到工具"->窗口"->键盘",则可能会在其中找到它们(因此可以设置快捷方式).

我将只显示原始的 Button (用于显示工具窗口)和仅用于快捷方式( Keybind )的第二个不可见的 Button ./p>

MyWindowPackage.vsct (分为几部分):

 <!-显示菜单中命令/按钮的定义,规范名称是您如何在VS中找到命令的方法.键盘->CommandName]-><命令package ="guidMyWindowPackage">< Button guid ="guidMyWindowPackageCmdSet"id ="MyWindowCommandId"优先级="0x0100"type ="Button"><父guid ="guidSHLMainMenu" id ="IDG_VS_WNDO_OTRWNDWS1"/>< Strings>< ButtonText>我的工具窗口</ButtonText>< CommandName> MyCommand</CommandName>< MenuText>我的工具窗口</MenuText>< LocCanonicalName> MyToolWindow</LocCanonicalName></字符串></按钮>< Button guid ="guidMyWindowPackageCmdSet"id ="MySaveCommandId"优先级="0x0100"type ="Button"><字符串>< ButtonText>我的工具窗口保存</ButtonText>< LocCanonicalName> MyToolWindow.Save</LocCanonicalName></字符串></按钮></按钮></命令> 

KeyBindings(快捷方式定义):

 < KeyBindings>< KeyBinding guid ="guidMyWindowPackageCmdSet"id ="MySaveCommandId"编辑器="guidVSStd97"key1 ="1" mod1 ="Control"/></KeyBindings> 

Symbols ,它们将 GUID Command定义 Command逻辑设置并绑定在一起:

 < Symbols><!-这是程序包guid.->< GuidSymbol name ="guidMyWindowPackage" value ="{00000000-0000-0000-0000-000000000003}""/><!-这是将菜单命令分组在一起的向导->< GuidSymbol name ="guidMyWindowPackageCmdSet" value ="{00000000-0000-0000-0000-000000000002}">< IDSymbol name ="MyWindowCommandId" value ="0x0100"/>< IDSymbol name ="MySaveCommandId" value ="0x0201"/></GuidSymbol><!-更多的GuidSymbols-></符号> 

奖金:

KeyBinding 确实具有属性 editor ="guidVSStd97" ,这会将绑定范围设置为"GENERAL"(可在每个窗口中使用).如果您可以将其设置为 ToolWindow GUID ,则仅在选择 ToolWindow 时使用.后面对此进行了描述链接.要完整完成,请访问

However the Command is never fired from the key-press, I think the issue(s) might be:

  • code above should not be working? (I found article where the bind should be done to the Command with DependencyProperty)
  • The key-press is caught by Visual Studio itself (CTRL + S is saving the file)
  • I might need to set the binding on the Window which encapsulates the UserControl
  • I might need to set the binding in the *Package.vsct and route it through as it would be a Command in Visual Studio

Question(s): How am I suppose to bind to the shortcut key-press? Where am I suppose to place the binding?

解决方案

KeyBindings seems complicated and needs to be definied on several steps (also depends on requirements). This answer is written as a bonus to answer of user1892538.

Scenario: We got toolWindow which is already showing, but we want to add some command, which will invoke method in the view/view-model.


1. Create new Command (Step 3 in this tutorial):

Right-click to the project -> Add New Item -> Custom command. This will create 2 files and modify file with package:

  • CommandName.png - icon for the menu
  • CommandName.cs - class file including the source code of command
  • ProjectWindowPackage.cs - Package class with Initialize() method, which invokes Initialize() of CommandName.cs

MyWindowPackage.cs:

public sealed class MyWindowPackage : Package
{
    public const string PackageGuidString = "00000000-0000-0000-0000-000000000003";

    public MyWindowPackage() { }

    protected override void Initialize()
    {
        MyToolWindowCommand.Initialize(this);
        MySaveCommand.Initialize(this);
        base.Initialize();
    }
}

CommandName.cs:

// these 2 values will do the binding
public static readonly Guid ApplicationCommands
                                  = new Guid("00000000-0000-0000-0000-000000000002");
public const int SaveCommandId = 0x0201;

private readonly Package package;

private CommandName(Package package)
{
    // we need to have package (from Initialize() method) to set VS
    if (package == null) throw new ArgumentNullException("package");
    this.package = package;

    // this provides access for the Menu (so we can add our Command during init)
    OleMenuCommandService commandService = this.ServiceProvider.GetService(typeof(IMenuCommandService)) as OleMenuCommandService;
    if (commandService != null)
    {
        // Creates new command "reference" (global ID)
        var menuCommandID = new CommandID(ApplicationCommands, SaveCommandId);
        // Create new command instance (method to invoke, ID of command)
        var menuItem = new MenuCommand(this.Save, menuCommandID);
        // Adding new command to the menu
        commandService.AddCommand(menuItem);
    }

    private void Save()
    {
        // Get instance of our window object (param false -> won't create new window)
        ToolWindowPane lToolWindow = this.package.FindToolWindow(typeof(MyToolWindow), 0, false);
        if ((null == lToolWindow) || (null == lToolWindow.Frame)) return;

        // Handle the toolWindow's content as Window (our control)
        ((lToolWindow as MyToolWindow)?.Content as MyWindowControl)?.Save();
    }
}


2. Set content of MyToolWindow to MyWindowControl (done when VSIX created):

MyToolWindow.cs:

[Guid("00000000-0000-0000-0000-000000000001")] //GUID of ToolWindow
public class MyToolWindow : ToolWindowPane
{
    public MyToolWindow() : base(null)
    {
        this.Content = new MyWindowControl();
    }
}


3. Set code in code-behind to invoke ViewModel (or do the job itself):

MyWindowControl.cs:

public partial class MyWindowControl : UserControl
{
    // output omitted for brevity

    public void Save()
    {
        // Do the call towards view-model or run the code

        (this.DataContext as MyViewModel)?.SaveCmd.Execute(null);
    }
}


4. Set Command with Shortcut so VS know how to handle them:

In MZTools' article can be found solution how to add Command without seeing it in menu, but if You will go to Tools->Window->Keyboard, You might find them there (so You can set up shortcut).

I will show both origin Button (for displaying tool window) and 2nd invisible Button used for the shortcut (Keybind) only.

MyWindowPackage.vsct (in several parts):

<!-- shows the definition of commands/buttons in menu, Canonical name is how You can find the command in VS [Tools -> Keyboard -> CommandName] -->
<Commands package="guidMyWindowPackage">

    <Button guid="guidMyWindowPackageCmdSet"
            id="MyWindowCommandId"
            priority="0x0100"
            type="Button">
    <Parent guid="guidSHLMainMenu" id="IDG_VS_WNDO_OTRWNDWS1" />
    <Strings>
      <ButtonText>My ToolWindow</ButtonText>
      <CommandName>MyCommand</CommandName>
      <MenuText>My ToolWindow</MenuText>
      <LocCanonicalName>MyToolWindow</LocCanonicalName>
    </Strings>
  </Button>

  <Button guid="guidMyWindowPackageCmdSet"
          id="MySaveCommandId"
          priority="0x0100"
          type="Button">
    <Strings>
      <ButtonText>My ToolWindow Save</ButtonText>
      <LocCanonicalName>MyToolWindow.Save</LocCanonicalName>
    </Strings>
  </Button>
</Buttons>
</Commands>

KeyBindings (shortcut definition):

<KeyBindings>
    <KeyBinding guid="guidMyWindowPackageCmdSet"
                id="MySaveCommandId"
                editor="guidVSStd97"
                key1="1" mod1="Control" />
</KeyBindings>

And the Symbols, which set and bind GUID, Command definition and Command logic together:

<Symbols>
    <!-- This is the package guid. -->
    <GuidSymbol name="guidMyWindowPackage" value="{00000000-0000-0000-0000-000000000003}" />

    <!-- This is the guid used to group the menu commands together -->
    <GuidSymbol name="guidMyWindowPackageCmdSet" value="{00000000-0000-0000-0000-000000000002}">
        <IDSymbol name="MyWindowCommandId" value="0x0100" />
        <IDSymbol name="MySaveCommandId" value="0x0201" />
    </GuidSymbol>

<!-- some more GuidSymbols -->

</Symbols>

Bonus:

KeyBinding does have property editor="guidVSStd97", this will set the scope of binding to "GENERAL" (useable in each window). If You can set this to the GUID of Your ToolWindow, it will be used only when the ToolWindow is selected. How it works, is described behind this link. And to acomplish it full, get to this link.

这篇关于VSIX窗口-执行ICommand的关键快捷方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆