在 MVVM Light 5.2.0.37222 中找不到 GalaSoft.MvvmLight.CommandWpf 命名空间

Cannot find GalaSoft.MvvmLight.CommandWpf namespace in MVVM Light 5.2.0.37222

我刚刚尝试将我的一个 WPF 项目从 MVVM Light 4.2.30 更新到 5.2。之后我注意到我的 RelayCommands 不再触发他们的 CanExecute 方法。

快速搜索后,我找到了几篇解释问题并建议使用 GalaSoft.MvvmLight.CommandWpf 命名空间而不是 GalaSoft.MvvmLight.Command 的文章。但是我找不到 GalaSoft.MvvmLight.CommandWpf 命名空间。当我查看 Visual Studio 的 'Object Browser' 中的 GalaSoft.MvvMGalaSoft.MvvmLight.dll 时,我也找不到此命名空间。

除了我,似乎没有其他人遇到这个问题 - 知道我做错了什么吗?

更新:

我创建了一个小示例项目,展示了我目前如何在 MVVM light 4.2.30 版中使用 RelayCommands 及其 CanExecute 方法:

public class ViewModel : ViewModelBase
{
    private bool _isReadOnly = false;

    public ViewModel ()
    {
        this.DoSomethingCommand = new RelayCommand(DoSomething, CanDoSomething);
    }

    public bool IsReadOnly
    {
        get
        {
            return _isReadOnly;
        }

        set
        {
            _isReadOnly = value;
            this.RaisePropertyChanged("IsReadOnly");

            // With MVVMLight 4.2.30.23246 I did not need to call the RaiseCanExecuteChanged on any of my RelayCommands
            // DoSomethingCommand.RaiseCanExecuteChanged(); 
        }
    }

    public RelayCommand DoSomethingCommand { get; set; }

    private bool  CanDoSomething()
    {
        return !this.IsReadOnly;
    }

    private void DoSomething()
    {
        MessageBox.Show("Let's break the MVVM idea...");
    }
}

视图的XAML代码为:

<Window x:Class="MVVMLight5.2CanExecuteTest.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:MVVMLight5._2CanExecuteTest"
    mc:Ignorable="d"
    Title="Test" Height="150" Width="200">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <CheckBox HorizontalAlignment="Center" Grid.Row="0" Grid.Column="0" Content="Is read only" IsChecked="{Binding IsReadOnly, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
    <Button Grid.Row="1" Grid.Column="0" Content="Break me" Command="{Binding DoSomethingCommand}"/>
</Grid>

我的目标是,如果我在视图中有一个使用 'DoSomethingCommand' 作为命令的按钮,那么当我的 IsReadOnly 属性 变为 false 时,该按钮应该被禁用。 当使用 MVVM light 4.2.30 时,到目前为止这没有任何额外的工作,但在 MVVM light 5.2 中我需要添加 DoSomethingCommand.RaiseCanExecuteChanged();使按钮在视图中禁用。

我能否通过新的 MVVM 轻型框架以某种方式获得旧行为?

TL;DR: 确保您有对 GalaSoft.MvvmLight.Platform 的引用,然后您可以使用 CommandWpf 命名空间。或者,仔细检查您是否正在链接 MVVM Light 的 .NET 4.5 版本;我认为您正在链接到 .NET 4.0 版本

Laurent(MVVMLight 的作者)实际上 addressed all of this on his blog。关于他创建不同命名空间的原因:

In the portable class library version of MVVM Light, there is no CommandManager.

...

The first obvious solution I considered was this: Move the RelayCommand out of the GalaSoft.MvvmLight.dll assembly and into the GalaSoft.MvvmLight.Platform.dll. Because this DLL is not a PCL (hence the “platform” name), it can contains platform-specific elements. If I move the RelayCommand there, it will work with the CommandManager just like before. However, it will not be available for PCL-based assemblies anymore, which is a real issue. That’s why I decided against this decision.

Instead, I decided to duplicate the RelayCommand class. If you check the WPF source code, you will see that this class is linked in the GalaSoft.MvvmLight assembly, and also in the GalaSoft.MvvmLight.Platform assembly. This is the same class! To avoid conflicts however, the one in the Platform assembly is declared in the GalaSoft.MvvmLight.CommandWpf namespace.

在这种情况下,我仍然对事情为什么会这样感到有点困惑。当我反汇编发布在 Nuget 上的库时,这是我看到的:

MvvmLightLibs.5.2.0.0\lib\net40(程序集版本 5.2.0.37222):

namespace GalaSoft.MvvmLight.Command
{
    /// <omitted, see below>
    public class RelayCommand<T> : ICommand
    {
        private readonly WeakAction<T> _execute;
        private readonly WeakFunc<T, bool> _canExecute;

        /// <summary>
        /// Occurs when changes occur that affect whether the command should execute.
        /// 
        /// </summary>
        public event EventHandler CanExecuteChanged;

MvvmLightLibs.5.2.0.0\lib\net45(程序集版本 5.2.0.37223):

namespace GalaSoft.MvvmLight.Command
{
    /// <omitted, see below>
    public class RelayCommand<T> : ICommand
    {
        private readonly WeakAction<T> _execute;
        private readonly WeakFunc<T, bool> _canExecute;

        /// <summary>
        /// Occurs when changes occur that affect whether the command should execute.
        /// 
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add
            {
                if (this._canExecute == null)
                    return;
                CommandManager.RequerySuggested += value;
            }
            remove
            {
                if (this._canExecute == null)
                    return;
                CommandManager.RequerySuggested -= value;
            }
        }

请注意,CanExecuteChanged 的 4.5 版本使用 CommandManager class,这就是为什么您不需要调用 RaiseCanExecuteChanged() 的原因。 4.0版本只是一个常规活动,所以需要你自己打电话RaiseCanExecuteChanged()

另请注意,两者的程序集版本不同,并且由于在您的问题中您说您使用的是 5.2.0.37222,所以我会说您使用的是4.0 库。这就是为什么我认为只要参考 4.5 版本就可以解决它。

不幸的是,我无法通过查看 source code. None of those three constants are defined in the .NET 4.0 version of the project 来弄清楚 为什么 这两个版本不同,那么为什么它不生成带有 CommandManager?