ICommand.CanExecute传递空,即使CommandParameter设置 [英] ICommand.CanExecute being passed null even though CommandParameter is set

查看:246
本文介绍了ICommand.CanExecute传递空,即使CommandParameter设置的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有我在哪里绑定一个棘手的问题文本菜单来一组的ICommand 衍生对象,并设置命令 CommandParameter 每个属性菜单项通过风格:

I have a tricky problem where I am binding a ContextMenu to a set of ICommand-derived objects, and setting the Command and CommandParameter properties on each MenuItem via a style:

<ContextMenu
    ItemsSource="{Binding Source={x:Static OrangeNote:Note.MultiCommands}}">
    <ContextMenu.Resources>
        <Style
            TargetType="MenuItem">
            <Setter
                Property="Header"
                Value="{Binding Path=Title}" />
            <Setter
                Property="Command"
                Value="{Binding}" />
            <Setter
                Property="CommandParameter"
                Value="{Binding Source={x:Static OrangeNote:App.Screen}, Path=SelectedNotes}" />
...



不过,虽然 ICommand.Execute(对象)被传递设置所选音符,因为它应该 ICommand.CanExecute(对象)(创建菜单时被调用)越来越通过空。我检查和调用之前选定的音符集合正确实例(事实上它分配在其声明中的价值,所以这是从来没有)。我想不通为什么CanEvaluate被获得通过

However, while ICommand.Execute( object ) gets passed the set of selected notes as it should, ICommand.CanExecute( object ) (which is called when the menu is created) is getting passed null. I've checked and the selected notes collection is properly instantiated before the call is made (in fact it's assigned a value in its declaration, so it is never null). I can't figure out why CanEvaluate is getting passed null.

推荐答案

我已确定,有在文本菜单的至少两个错误,导致其CanExecute呼叫是在不同的情况下不可靠的。当命令设置它立即调用CanExecute。后来电话是不可预测的,肯定是不可靠的。

I have determined that there are at least two bugs in ContextMenu that causes its CanExecute calls to be unreliable in different circumstances. It calls CanExecute immediately when the Command is set. Later calls are unpredictable and certainly not reliable.

我花了一整个晚上曾经试图追查下,它会失败,并寻找一个解决办法的具体条件。最后,我放弃了,并切换到单击发射所需的命令处理程序。

I spent a whole night once trying to track down the precise conditions under which it would fail and looking for a workaround. Finally I gave up and switched to Click handlers that fired the desired commands.

我没有确定我的问题之一是,改变了文本菜单的DataContext的可导致CanExecute到新的命令或CommandParameter势必之前调用。

I did determine that one of my problems was that changing the DataContext of the ContextMenu can cause CanExecute to be called before the new Command or CommandParameter is bound.

我知道这个问题是使用自己的附加属性为命令,而是的CommandBinding使用内置的最佳解决方案-in的:

The best solution I know of to this problem is use your own attached properties for Command and CommandBinding instead of using the built-in ones:


  • 当您连接命令属性设置,订阅点击和DataContextChanged仅事件的菜单项,并且还订阅CommandManager.RequerySuggested。

  • When your attached Command property is set, subscribe to the Click and DataContextChanged events on the MenuItem, and also subscribe to CommandManager.RequerySuggested.

在DataContext的变化,RequerySuggested进来,或任你的两个附加属性的变化,计划使用Dispatcher.BeginInvoke的调度操作这将调用CanExecute(),并在菜单项更新IsEnabled。

When the DataContext changes, RequerySuggested comes in, or either of your two attached properties changes, schedule a dispatcher operation using Dispatcher.BeginInvoke that will call your CanExecute() and update IsEnabled on the MenuItem.

在Click事件触发,执行CanExecute的事情,如果通过,调用execute( 。)

When the Click event fires, do the CanExecute thing and if it passes, call Execute().

用法就像普通的命令和CommandParameter,但使用的附加属性,而不是:

Usage is just like regular Command and CommandParameter, but using the attached properties instead:

<Setter Property="my:ContexrMenuFixer.Command" Value="{Binding}" />
<Setter Property="my:ContextMenuFixer.CommandParameter" Value="{Binding Source=... }" />



此解决方案,并绕过所有与文本菜单的CanExecute处理错误的问题。

This solution works and bypasses all the problems with the bugs in ContextMenu's CanExecute handling.

希望有一天微软将修复与文本菜单的问题,这种解决方法将不再是必要的。我有一个摄制情况下坐在这里周围的地方,我打算向连接。也许我应该得到的球,并真正做到这一点。

Hopefully someday Microsoft will fix the problems with ContextMenu and this workaround will no longer be necessary. I have a repro case sitting around here somewhere that I intend to submit to Connect. Perhaps I should get on the ball and actually do it.

什么是RequerySuggested,为什么使用它?

RequerySuggested机制是有效地处理ICommand.CanExecuteChanged的RoutedCommand的方式。在非的RoutedCommand世界中,每个的ICommand有它自己的订户CanExecuteChanged的清单,但为的RoutedCommand,任何客户端订阅ICommand.CanExecuteChanged实际上将订阅CommandManager.RequerySuggested。这个简单的模型意味着,任何时候的RoutedCommand的CanExecute可能会改变,一切必要的是调用CommandManager.InvalidateRequerySuggested(),它会做同样的事情射击ICommand.CanExecuteChanged但同时并在后台线程做所有RoutedCommands。此外,RequerySuggested调用结合在一起,这样,如果很多变化发生CanExecute只需要调用一次。

The RequerySuggested mechanism is RoutedCommand's way of efficiently handling ICommand.CanExecuteChanged. In the non-RoutedCommand world, each ICommand has its own list of subscribers to CanExecuteChanged, but for RoutedCommand, any client subscribing to ICommand.CanExecuteChanged will actually subscribe to CommandManager.RequerySuggested. This simpler model means that any time a RoutedCommand's CanExecute may change, all that is necessary is to call CommandManager.InvalidateRequerySuggested(), which will do the same things as firing ICommand.CanExecuteChanged but do it for all RoutedCommands simultaneously and on a background thread. In addition, RequerySuggested invocations are combined together so that if many changes occur the CanExecute only needs to be called once.

我推荐的理由你订阅CommandManager.RequerySuggested代替ICommand.CanExecuteChanged是:1。你不需要的代码,以消除旧的订阅和每一个你的命令附加属性的值的变化而变化时添加一个新的,和2 CommandManager.RequerySuggested内置了允许弱引用功能您可以设置事件处理程序,仍然是垃圾收集。做同样与ICommand的需要你实现自己的弱引用机制。

The reasons I recommended you subscribe to CommandManager.RequerySuggested instead of ICommand.CanExecuteChanged is: 1. You don't need code to removing your old subscription and add a new one every time the value of your Command attached property changes changes, and 2. CommandManager.RequerySuggested has a weak reference feature built in that allows you to set your event handler and still be garbage collected. Doing the same with ICommand requires you to implement your own weak reference mechanism.

这样做的另一面是,如果你订阅CommandManager.RequerySuggested代替ICommand.CanExecuteChanged是你只能得到RoutedCommands更新。我用RoutedCommands只所以这不是我的问题,但我应该提到,如果你使用普通的个ICommand有时你应该考虑做弱订阅ICommand.CanExecutedChanged额外的工作。请注意,如果你这样做,你不需要订阅RequerySuggested为好,因为RoutedCommand.add_CanExecutedChanged已经这样做了你。

The flip side of this is that if you subscribe to CommandManager.RequerySuggested instead of ICommand.CanExecuteChanged is that you will only get updates for RoutedCommands. I use RoutedCommands exclusively so this is not an issue for me, but I should have mentioned that if you use regular ICommands sometimes you should consider doing the extra work of weakly subscribing to ICommand.CanExecutedChanged. Note that if you do this, you don't need to subscribe to RequerySuggested as well, since RoutedCommand.add_CanExecutedChanged already does this for you.

这篇关于ICommand.CanExecute传递空,即使CommandParameter设置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆