更新Mvvm Light到版本5后,我需要做哪些更改才能使RelayCommand的CanExecute()正常工作?

8
我将Mvvm Light更新到5版本后发现RelayCommand无法正常工作。
问题似乎是CanExecute()没有被调用进行验证。它仅在窗口加载时验证一次。
这可能是最近更新的一个错误,还是我需要在XAML中做出一些改变?
更新前一切都正常。 我正在使用WPF。

同样的问题,应该在之前找到你的帖子。我不得不降级回到以前的版本。 - Vojtěch Dohnal
2个回答

11
请查看此MVVM Light 5问题

WPF是唯一使用CommandManager自动触发ICommands的CanExecuteChanged事件的XAML框架。我从未喜欢过这种方法,因为其中包含了“魔法”部分,但这是WPF的一个“特性”,当然我必须支持它。这里没有问题。

在V5中,我将所有最新版本的XAML框架,包括WPF4.5,移植到便携式类库中。不幸的是,在PCL中没有CommandManager,我必须承认一开始没有意识到这一点。所以现在自动触发命令的部分不再起作用了。再次,非常抱歉。

我不希望您现在在所有地方都触发CanExecuteChanged,而是在应用程序中使用CommandManager,这是WPF团队的原意。因此,我将尝试找到一种方法来在工具包的WPF4.5版本中恢复使用CommandManager。

肯定不是在找借口;)但希望解释一下为什么会出现这个问题有助于理解。直到我在PCL版本中找到解决方法之前,这将是我的首要任务。同时,如我之前所提到的,回到V4.4.32.7应该可以解决这个问题。如果不能,请告诉我。

因此,暂时推荐的解决方案是恢复到先前版本。我尝试了一下,确实有效。

我同意CommandManager正在进行“魔法”。有一次在CanExecute条件中出现了空引用异常,结果我得到了无休止的错误消息循环,就像Windows纸牌游戏中的卡片一样。如果我开始一个新项目,我宁愿不使用这种“魔法”,但更改一个已经部署的项目将非常痛苦。


4
修复于5.0.2版本。 - Vojtěch Dohnal
20
请确保将命名空间从GalaSoft.MvvmLight.Command;更改为GalaSoft.MvvmLight.CommandWpf;才能在v5.0.2中使用该修复程序。 - mips

1
看起来当相关属性发生变化时,您需要调用命令上的RaiseCanExecuteChanged。我认为这以前是由WPF命令管理器完成的,但最近的PCL更改可能使其不受支持。
我使用MvvmCross,它需要调用类似的方法,因此在我的基本视图模型中,我有一个方法允许我注册一个命令,这样每当发生属性更改时,我可以循环所有已注册的命令并强制再次调用canexecute。为了使事情更容易,您可以这样做。 查看此示例 由于这似乎受到质疑,这里是我测试过的一些代码
using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System;

namespace TestingApp.ViewModel
{
    /// <summary>
    /// This class contains properties that the main View can data bind to.
    /// <para>
    /// Use the <strong>mvvminpc</strong> snippet to add bindable properties to this ViewModel.
    /// </para>
    /// <para>
    /// You can also use Blend to data bind with the tool's support.
    /// </para>
    /// <para>
    /// See http://www.galasoft.ch/mvvm
    /// </para>
    /// </summary>
    public class MainViewModel : ViewModelBase
    {
        private Int32 _increment = 0;

        public Int32 Increment
        {
            get { return _increment; }
            set
            {
                _increment = value;
                RaisePropertyChanged("Increment");
                GoCommand.RaiseCanExecuteChanged();
            }
        }

        /// <summary>
        /// Initializes a new instance of the MainViewModel class.
        /// </summary>
        public MainViewModel()
        {
            ////if (IsInDesignMode)
            ////{
            ////    // Code runs in Blend --> create design time data.
            ////}
            ////else
            ////{
            ////    // Code runs "for real"
            ////}
        }

        private RelayCommand _incrementCommand;

        public RelayCommand IncrementCommand
        {
            get
            {
                if (_incrementCommand == null)
                {
                    _incrementCommand = new RelayCommand(IncrementCommand_Execute);
                }
                return _incrementCommand;
            }
        }

        private void IncrementCommand_Execute()
        {
            Increment++;
        }

        private RelayCommand _goCommand;

        public RelayCommand GoCommand
        {
            get
            {
                if (_goCommand == null)
                {
                    _goCommand = new RelayCommand(GoCommand_Execute, GoCommand_CanExecute);
                }
                return _goCommand;
            }
        }

        private bool GoCommand_CanExecute()
        {
            return Increment > 5;
        }

        private void GoCommand_Execute()
        {
            //
        }
    }
}

没有

这一行
GoCommand.RaiseCanExecuteChanged();

在初始调用后,canexecute方法将不会被再次调用,但是使用该行代码,每当Increment属性更改时它都会被调用。


也许如果你真的尝试了我的建议,你会发现我是正确的。所以我认为这是一个非常有帮助的答案。我添加了一些额外的示例代码,我已经测试过它可以工作。 - ndonohoe
想象一下,你有一个项目,必须经过数百个这样的情况,并再次测试所有内容。你愿意这样做吗? - Vojtěch Dohnal
我同意對於已經具有許多命令的大型項目來說,這並不是最好的選擇。但是對於那些剛開始使用MVVMLight的人來說,這可能會節省他們的時間。 - ndonohoe

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接