VSIX窗口-执行ICommand的关键快捷方式 [英] VSIX window - key shortcut to execute 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
的 - 我可能需要在
* Package.vsct
中设置绑定,并通过它进行路由,因为这将成为Visual Studio中的Command
.
Window
上设置绑定问题:我应该如何绑定到快捷键?我应该在哪里放置绑定?
KeyBindings
似乎很复杂,需要在几个步骤上进行定义(也取决于要求).此答案是对 user1892538 的回答的补充.
场景::我们已经显示了toolWindow,但是我们想添加一些命令,该命令将在view/view-model中调用方法.
1.在
右键单击项目->添加新项
-> 自定义命令
.这将创建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-></符号>
奖金:
However the Question(s): How am I suppose to bind to the shortcut key-press? Where am I suppose to place the binding? 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 Right-click to the project -> Add
2. Set content of MyToolWindow to MyWindowControl (done when VSIX created):
3. Set code in code-behind to invoke ViewModel (or do the job itself):
4. Set In MZTools' article can be found solution how to add I will show both origin KeyBindings (shortcut definition): And the Bonus: 这篇关于VSIX窗口-执行ICommand的关键快捷方式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋! KeyBinding
确实具有属性 editor ="guidVSStd97"
,这会将绑定范围设置为"GENERAL"(可在每个窗口中使用).如果您可以将其设置为 ToolWindow
的 GUID
,则仅在选择 ToolWindow
时使用.后面对此进行了描述链接.要完整完成,请访问Command
is never fired from the key-press, I think the issue(s) might be:
Command
with DependencyProperty
)Window
which encapsulates the UserControl
*Package.vsct
and route it through as it would be a Command
in Visual StudioKeyBindings
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.
Command
(Step 3 in this tutorial):New Item
-> Custom command
. This will create 2 files and modify file with package:
CommandName.png
- icon for the menuCommandName.cs
- class file including the source code of commandProjectWindowPackage.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();
}
}
MyToolWindow.cs
:[Guid("00000000-0000-0000-0000-000000000001")] //GUID of ToolWindow
public class MyToolWindow : ToolWindowPane
{
public MyToolWindow() : base(null)
{
this.Content = new MyWindowControl();
}
}
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);
}
}
Command
with Shortcut
so VS know how to handle them: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).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>
<KeyBinding guid="guidMyWindowPackageCmdSet"
id="MySaveCommandId"
editor="guidVSStd97"
key1="1" mod1="Control" />
</KeyBindings>
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>
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.