C# 可在RelayCommand上执行<;T>;不起作用

C# 可在RelayCommand上执行<;T>;不起作用,c#,wpf,mvvm,relaycommand,C#,Wpf,Mvvm,Relaycommand,我正在使用MVVM Light V3 alpha 3编写一个WPF 4应用程序(带VS2010 RC),在这里遇到了一些奇怪的行为 我有一个命令可以打开一个窗口,该窗口会创建ViewModel等等-没有什么奇怪的 在该窗口中我有一些RelayCommands,例如: CategoryBeenSelected = new RelayCommand(() => OnCategoryUpdate = true); <Button Content="Fit To Width

我正在使用MVVM Light V3 alpha 3编写一个WPF 4应用程序(带VS2010 RC),在这里遇到了一些奇怪的行为

我有一个命令可以打开一个
窗口
,该窗口会创建ViewModel等等-没有什么奇怪的

在该
窗口中
我有一些
RelayCommand
s,例如:

CategoryBeenSelected = new RelayCommand(() => OnCategoryUpdate = true);
        <Button Content="Fit To Width" Command="{Binding Path=FitToWidthCommand}" CommandParameter="{Binding ElementName=imageScrollViewer, Path=ActualWidth}" />
        <Button Content="Fit To Height" Command="{Binding Path=FitToHeightCommand}" CommandParameter="{Binding ElementName=imageScrollViewer, Path=ActualHeight}" />
再也没有什么奇怪的了-它像我预期的那样工作

问题是我不能用泛型RelayCommand创建CanExecute方法/lambda表达式

这项工作:

DeleteCategoryCommand = new RelayCommand<int>(DeleteCategory);

此时,参数可能是
null

似乎RelayCommand会将参数的值转换为泛型T

但是,正如异常告诉您的那样,您不能将null强制转换为结构

如果使用可为空的结构初始化RelayCommand,它将按预期工作

RelayCommand<int?> or RelayCommand<Nullable<int>>
RelayCommand或RelayCommand

HTH

大角星在确定问题所在方面是正确的,但是我不喜欢使用可空原语的解决方案。我个人不喜欢可为空的原语,除非我有很好的理由使用它们

相反,我将RelayCommand的实现更改如下:

    bool ICommand.CanExecute(object parameter)
    {
        if (parameter == null && typeof(T).IsValueType)
        {
            return CanExecute(default(T));
        }
        return CanExecute((T)parameter);
    }
我没有对泛型Execute方法做同样的更改(至少现在是这样),因为我认为如果命令确实需要参数,那么在这种情况下失败是不合理的

CanExecute的问题是WPF系统有时会在评估某些绑定之前调用它。例如:

CategoryBeenSelected = new RelayCommand(() => OnCategoryUpdate = true);
        <Button Content="Fit To Width" Command="{Binding Path=FitToWidthCommand}" CommandParameter="{Binding ElementName=imageScrollViewer, Path=ActualWidth}" />
        <Button Content="Fit To Height" Command="{Binding Path=FitToHeightCommand}" CommandParameter="{Binding ElementName=imageScrollViewer, Path=ActualHeight}" />

在上面的XAML中,您注意到命令参数绑定到控件的实际宽度。但是,WPF将在“imageScrollViewer”控件必须布局/渲染之前调用按钮命令上的CanExecute,因此没有实际的宽度/高度。当然,当用户单击按钮并调用Execute时,控件的布局会将值发送到命令。如果没有-我认为失败是应该预期的-但只有当用户实际单击按钮时


当然,我不喜欢CanExecute和Execute的不同行为,但目前它似乎符合框架提出的限制。我可能会觉得这会让我感到悲伤,但到目前为止,我一直很喜欢这种变化。

参加派对的时间非常晚,但我一直在为这件事挠头,问题是我导入了错误的名称空间

我应该输入:

使用GalaSoft.MvvmLight.CommandWpf

但我输入了:

使用GalaSoft.MvvmLight.Command


希望这对别人有帮助

也许你可以附加一个堆栈跟踪?这可能有助于理解出了什么问题。对不起,我忘了,就是这样:)这很奇怪:Reflector告诉我们函数
CanExecute
是这样定义的:
public bool CanExecute(object parameter){return(this.\u CanExecute==null)| this.\u CanExecute((T)parameter))}
。没有什么可以抛出异常。也许你可以试着在一个较小的例子中重现这个问题?啊哈,我得到了一些新的东西。如果您有一个带有字符串或对象的RelayCommand,它就可以工作,如果您使用其他东西(int、bool、double…),它就会死掉。不管你是否真的发送了一个参数。关于这个例子。它发生在WPF3.5/Mvvm light 2和WPF4/Mvvm light 3 alpha3中。你会跑什么?(我不知道您是否需要MVVM light安装程序)嗯,这应该是原因。。。但这有点奇怪。。我没有看到任何代码使用nullable…是的,这是正确的。。
double
int
是值类型,不能为null。如果将它们设置为可为null的类型,则应该可以正常工作。将
null
强制转换为结构将产生异常!使用方法查看Vlads注释,您可以在其中看到T!尝试编译双重测试=(双重)null;。。在一般情况下,您将得到一个运行时异常!;)