解决WPF中ContextMenu绑定RoutedCommand时第一次无法执行的问题 Original yycoding Friday, April 15, 2022 China Standard
2022/7/26 23:25:12
本文主要是介绍解决WPF中ContextMenu绑定RoutedCommand时第一次无法执行的问题 Original yycoding Friday, April 15, 2022 China Standard,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
WPF中RoutedCommand是一个非常实用的功能,它能够将某一命令绑定到多个控件上,比如同一个命令可以绑定到Button,Menu,ContextMenu上,这样不但可以避免重复,还可以统一行为。但初次使用RoutedCommand时我就遇到了一个很奇怪的Bug,就是将右键弹出菜单ContextMenu的某一个菜单MenuItem和窗体上的某个Button同时绑定到了某一个命令RoutedUICommand上。当程序初次运行时,ContextMenu里面的绑定了命令的菜单是灰色的,不可用,即使设置IsEnable=true,也不行。而Button却是正常的,但在点击Button执行一次命令后,ContextMenu里面的菜单就变得可用了。
在一顿搜索之后发现了这篇文章How to Solve Execution Problems of RoutedCommands in a WPF ContextMenu,完美的解决了这一问题。
问题
其实这个问题在上面这个链接里说的非常清楚,我这里还是以NTP时间同步这个应用的代码来说明一下情况。在app.xaml的Resouce中我定义了一个RoutedUICommand,Key为"SyncNow",表示用来同步时间:
<Application x:Class="NTPClock.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" Startup="AppOnStartup" StartupUri="MainWindow.xaml" > <Application.Resources> <ResourceDictionary> <RoutedUICommand x:Key="SyncNow" /> </ResourceDictionary> </Application.Resources> </Application>
紧接着在MainWindow中定义了这个命令的执行委托:
<Window.CommandBindings> <CommandBinding Command="{StaticResource SyncNow}" Executed="CommandBinding_Executed"/> </Window.CommandBindings>
紧接着定义了一个ContextMenu里面添加了一个MenuItem,绑定了这个命令。
<Grid.ContextMenu> <ContextMenu Name="gridContextMenu"> <MenuItem Header="{DynamicResource S.TimeSetting.SyncNow}" Command="{StaticResource SyncNow}" /> </ContextMenu> </Grid.ContextMenu>
在窗体的Button上也绑定了这个方法:
<Button VerticalAlignment="Center" Name="btnSync" Command="{StaticResource SyncNow}" />
原因
原因在于ContextMenu是一个独立的窗体,它有自己的视觉树和逻辑树。CommandManager会在当前聚焦的范围(focus scope)内查找绑定,如果当前的聚焦范围内没有命令绑定,它会在其父聚焦范围内查找。当应用程序启动时,主窗体的聚焦范围还没有被设定。调用FocusManager.GetFocusElement(this)可以看到他会返回null。
解决方法
最简单的解决方法是,在程序启动后,在构造函数里调用Focus方法,手动设置聚焦范围。
public MainWindow() { InitializeComponent(); this.Closed += delegate { Application.Current.Shutdown(); }; Focus(); }
或者在xaml里面 定义:
<controls:MetroWindow x:Class="NTPClock.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:NTPClock" mc:Ignorable="d" Icon="NTPClock.ico" ShowIconOnTitleBar="True" Title="{DynamicResource S.Title}" FocusManager.FocusedElement="{Binding RelativeSource={x:Static RelativeSource.Self}, Mode=OneTime}" Height="450" Width="550" ResizeMode="CanMinimize" Loaded="MainWindow_OnLoaded"> </controls:MetroWindow>
这样,CommandManager就能在其父窗体控件的聚焦范围内找到对应的命令绑定。
还有一种方法是设置CommandTarget对象:
<MenuItem Header="{DynamicResource S.TimeSetting.SyncNow}" Command="{StaticResource SyncNow}" CommandTarget="{Binding Path=PlacementTarget,RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type ContextMenu}}}" >
待解决的问题
在我的程序中,在使用handycontrol添加了一个托盘菜单,托盘菜单里也有一个同步菜单,这个菜单目前还无法绑定到SyncNow命令上,参考开源项目GifRecorder,可能解决的方法是把这些命令放到ViewModel里,然后设置DataContext,就能解决吧。目前还是直接使用Click事件来处理的,不够优雅。
总结
由于ContextMenu跟窗体都有自己独立的视觉树和逻辑树,所以在将ContextMenu与RoutedCommand绑定时,第一次运行时,由于主窗体的聚焦范围(focus scope)没有被设定,导致CommandManager找不到对应的绑定命令,从而使得ContextMenu里面的MenuItem不可用,这是一个非常常见的问题。解决方法是在主窗体的构造函数里调用Focus方法,或者手动设置MenuItem的CommandTarget属性。
转载:https://www.yycoding.xyz/post/2022/4/15/solve-execution-problems-of-contextmenu-binding-routedcommands-in-wpf
这篇关于解决WPF中ContextMenu绑定RoutedCommand时第一次无法执行的问题 Original yycoding Friday, April 15, 2022 China Standard的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-22怎么实现ansible playbook 备份代码中命名包含时间戳功能?-icode9专业技术文章分享
- 2024-11-22ansible 的archive 参数是什么意思?-icode9专业技术文章分享
- 2024-11-22ansible 中怎么只用archive 排除某个目录?-icode9专业技术文章分享
- 2024-11-22exclude_path参数是什么作用?-icode9专业技术文章分享
- 2024-11-22微信开放平台第三方平台什么时候调用数据预拉取和数据周期性更新接口?-icode9专业技术文章分享
- 2024-11-22uniapp 实现聊天消息会话的列表功能怎么实现?-icode9专业技术文章分享
- 2024-11-22在Mac系统上将图片中的文字提取出来有哪些方法?-icode9专业技术文章分享
- 2024-11-22excel 表格中怎么固定一行显示不滚动?-icode9专业技术文章分享
- 2024-11-22怎么将 -rwxr-xr-x 修改为 drwxr-xr-x?-icode9专业技术文章分享
- 2024-11-22在Excel中怎么将小数向上取整到最接近的整数?-icode9专业技术文章分享