c# - VSIX 窗口 - 执行 ICommand 的快捷键

标签 c# wpf xaml vsix envdte

有一个 Visual Studio 扩展 (VSIX) 项目:在 Window 中,我们得到了 UserControl,它有 Button 绑定(bind)到一些 ICommand 。这完全符合预期,但我想附加一个快捷键(例如:CTRL + S),它会触发相同的 Command

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

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

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

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

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

最佳答案

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

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


<强>1。创建新的命令(this 教程中的第 3 步):

右键单击项目 -> 添加新项 -> 自定义命令。这将创建 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();
    }
}

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。将 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();
    }
}

<强>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);
    }
}

<强>4。将 Command 设置为 Shortcut 以便 VS 知道如何处理它们:

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

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

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>

KeyBindings(快捷键定义):

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

还有Symbols,它们将GUID命令定义命令逻辑设置并绑定(bind)在一起:

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

奖励:

KeyBinding 确实有属性 editor="guidVSStd97",这会将绑定(bind)范围设置为“GENERAL”(可在每个窗口中使用)。如果您可以将此设置为您的 ToolWindowGUID,则只有在选择 ToolWindow 时才会使用它。它是如何工作的,描述了behind this link .要完成它,请前往 this link .

关于c# - VSIX 窗口 - 执行 ICommand 的快捷键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42764348/

相关文章:

c# - Label.Content 无法正常工作

c# - 在 WPF 中,如何引用在不同 XAML 文件中定义的静态资源?

wpf - 如何使用 IsEnabled 来禁用 Expander 的部分而不是全部?

c# - WPF,如何在选择后重置组合框

c# - WPF 从动态图像向代码隐藏发送值?

wpf - 使用控件模板创建图像+文本按钮?

c# - 如何让SqlConnection超时更快

c# - 在 ASP.NET MVC 3 中,什么是 filterContext.IsChildAction?

c# - javascript - 复选框 checkall() 函数

c# - DataBind 一个控件到另一个控件