将 WPF 命令与 Canvas 结合使用不起作用

发布于 2024-09-03 00:50:02 字数 872 浏览 5 评论 0原文

我有一个从 Canvas 派生的自定义画布。它包含一些像 New/Open/Save 等这样添加的 ApplicationCommands -

this.CommandBindings.Add(new CommandBinding(ApplicationCommands.New, New_Executed, 
New_Enabled));

New_Enabled 始终返回 true。

该控件用在有菜单栏的wpf项目中;此菜单栏中存在“新建/打开/保存”菜单按钮,其 Command 设置为相应的 ApplicationCommand,如下所示 -

<syncfusion:SimpleMenuButton
    x:Name="NewMenu"
    Icon="Images\New_Large.png"
    Label="New"
    IsEnabled="True"
    Command="{x:Static ApplicationCommands.New}"
    syncfusion:Ribbon.KeyTip="N">
</syncfusion:SimpleMenuButton>

当焦点位于 Canvas< 上时,命令可以正常工作/code> 但一旦焦点转移到其他控件,“新建”按钮就会被禁用。我尝试将 CommandTarget 设置为主窗口,但这也不起作用。

为什么会发生这种情况以及如何确保“新菜单”按钮始终处于启用状态?

I am having a custom canvas derived from Canvas. It contains few ApplicationCommands like New/Open/Save etc. added like this -

this.CommandBindings.Add(new CommandBinding(ApplicationCommands.New, New_Executed, 
New_Enabled));

New_Enabled always returns true.

This control is used in a wpf project having a menu bar; New/Open/Save menu button's are present in this menu bar with their Command set to respective ApplicationCommand like this -

<syncfusion:SimpleMenuButton
    x:Name="NewMenu"
    Icon="Images\New_Large.png"
    Label="New"
    IsEnabled="True"
    Command="{x:Static ApplicationCommands.New}"
    syncfusion:Ribbon.KeyTip="N">
</syncfusion:SimpleMenuButton>

Command works correctly when focus is present on Canvas but as soon as focus shifts to other control, New button gets disabled. I have tried setting CommandTarget to main window but that too doesn't work.

Why this is happening and how can to make sure that New menu button will always be enabled?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

网名女生简单气质 2024-09-10 00:50:02

问题是,一旦您的按钮和画布共享层次结构上方某处的逻辑焦点范围(很可能是您的窗口),某些菜单中启动的命令永远不会到达您的画布。

如果您只有一个画布,想要接收所有命令,只需将按钮的 CommandTarget 绑定到画布:

...
Command="New"
CommandTarget="{Binding ElementName=TheCanvas}"
...

请注意,ICommand 标记有 TypeConverterAttribute 会将“New”等字符串转换为 ApplicationCommands.New,因此您不必使用 x:Static 标记扩展。

您可以在一个地方使用 Style 为菜单/工具栏级别上的所有按钮完成此操作。

但是,如果您有多个画布并希望您的命令定向到当前聚焦的画布,则必须执行两件事:

  1. 确保您的画布(或其上的控件)具有 Focusable="True"
  2. 通过设置 FocusManager.IsFocusScope="True" 来限制工具栏(或用于按钮的任何容器)的逻辑焦点范围。某些容器(例如菜单或工具栏)默认情况下处于启用状态。这样,一旦命令路由算法到达范围,它就会将其重定向到当前具有键盘焦点的元素。

The problem is that once your button and canvas share logical focus scope somewhere above in the hierarchy (most likely it is your window) the commands initiated in some menu never reach your canvas.

If you have just one canvas which you want to receive all your commands, just bind CommandTarget of your buttons to canvas:

...
Command="New"
CommandTarget="{Binding ElementName=TheCanvas}"
...

Note that ICommand is marked with TypeConverterAttribute which converts strings like "New" to ApplicationCommands.New so you don't have to use x:Static markup extension.

You can do it in one place with Style for all buttons on the level your menu/toolbar.

However, if you have multiple canvases and want your command to be directed towards currently focused one, you have to do two things:

  1. make sure your canvas (or a control on it) has Focusable="True"
  2. limit the logical focus scope of your toolbar (or whatever container you use for your buttons) by setting FocusManager.IsFocusScope="True" on it. Some containers, like Menu, or ToolBar have that on by default. This way once command routing algorithm reaches the scope it will redirect it to the element currently having the keyboard focus.
站稳脚跟 2024-09-10 00:50:02

@repka - 感谢您的回复;我已经尝试使用画布名称作为 CommandTarget 但它不起作用;仅当焦点位于画布上时,按钮才会启用,一旦我单击窗口中的某些其他控件,按钮就会被禁用。我也尝试使用 IsFocusScope 但结果相同。感谢您提供命令名称字符串提示。

我不得不接受这个解决方法,尽管我对此不太满意 -

    public WindowMain()
    {
        InitializeComponent();

        //Add commnad bindings
        //Need to do this to keep New/Open/Save/Run buttons always enabled
        //ToDo:[AJ] Look for better solution then this
        this.CommandBindings.Add(new CommandBinding(ApplicationCommands.New, this.TheCanvas.New_Executed, this.TheCanvas.New_Enabled));
        this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, this.TheCanvas.Open_Executed, this.TheCanvas.Open_Enabled));
        this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Save, this.TheCanvas.Save_Executed, this.TheCanvas.Save_Enabled));
        this.CommandBindings.Add(new CommandBinding(RTDesignerCanvas.Run, this.TheCanvas.Run_Executed));
    }

@repka - Thanks for your response; I had already tried using canvas name as CommandTarget but it doesn't work; Buttons gets enabled only when focus is on canvas as soon as i Click on some other control in window they gets disabled. I also tried using IsFocusScope but same result. Thanks for the command name strings tip.

I had to settle with this workaround, although I am not too happy with this -

    public WindowMain()
    {
        InitializeComponent();

        //Add commnad bindings
        //Need to do this to keep New/Open/Save/Run buttons always enabled
        //ToDo:[AJ] Look for better solution then this
        this.CommandBindings.Add(new CommandBinding(ApplicationCommands.New, this.TheCanvas.New_Executed, this.TheCanvas.New_Enabled));
        this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Open, this.TheCanvas.Open_Executed, this.TheCanvas.Open_Enabled));
        this.CommandBindings.Add(new CommandBinding(ApplicationCommands.Save, this.TheCanvas.Save_Executed, this.TheCanvas.Save_Enabled));
        this.CommandBindings.Add(new CommandBinding(RTDesignerCanvas.Run, this.TheCanvas.Run_Executed));
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文