VSIX 窗口 - 执行 ICommand 的快捷键

Tat*_*ved 3 c# wpf xaml envdte vsix

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

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

<UserControl.InputBindings>
    <KeyBinding Modifiers="Ctrl" Key="Esc" Command="{Binding SaveCmd}"/>
</UserControl.InputBindings>
Run Code Online (Sandbox Code Playgroud)

然而,Command从来没有被按键触发,我认为问题可能是:

  • 上面的代码不应该工作?(我发现应该对Commandwith进行绑定的文章DependencyProperty
  • 按键被 Visual Studio 本身捕获(CTRL+S正在保存文件)
  • 我可能需要在Window封装了UserControl
  • 我可能需要在 中设置绑定*Package.vsct并将其路由,就像Command在 Visual Studio 中一样

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

Tat*_*ved 5

KeyBindings看起来很复杂,需要定义几个步骤(也取决于要求)。这个答案是作为user1892538答案的奖励而写的

场景:我们得到了已经显示的 toolWindow,但我们想添加一些命令,它将调用视图/视图模型中的方法。


1.创建新的Command步骤3这个教程):

右键单击项目 -> 添加New Item-> Custom command。这将创建 2 个文件并使用包修改文件:

  • CommandName.png-菜单图标
  • CommandName.cs-包含命令源代码的类文件
  • ProjectWindowPackage.cs-套餐类Initialize()方法,这将调用Initialize()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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

MyToolWindow.cs

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

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

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

4.设置CommandShortcut让VS知道如何处理它们:

MZTools 的文章中可以找到如何Command在菜单中不看到它的情况下添加的解决方案,但是如果您转到 Tools->Window->Keyboard,您可能会在那里找到它们(因此您可以设置快捷方式)。

我将同时显示原点Button(用于显示工具窗口)和仅Button用于快捷方式 ( Keybind) 的2nd invisible 。

MyWindowPackage.vsct (分几个部分):

<!-- 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>
Run Code Online (Sandbox Code Playgroud)

KeyBindings(快捷方式定义):

<KeyBindings>
    <KeyBinding guid="guidMyWindowPackageCmdSet"
                id="MySaveCommandId"
                editor="guidVSStd97"
                key1="1" mod1="Control" />
</KeyBindings>
Run Code Online (Sandbox Code Playgroud)

Symbols, 设置和绑定GUIDCommand definitionCommand logic在一起:

<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>
Run Code Online (Sandbox Code Playgroud)

奖金:

KeyBinding确实有属性editor="guidVSStd97",这会将绑定范围设置为“GENERAL”(可在每个窗口中使用)。如果您可以将其设置GUID为 Your 的ToolWindow,则仅在ToolWindow选择时才会使用它。它是如何工作的,在这个链接后面有描述。要完成它,请访问此链接