CanExecute on RelayCommand <T>无法正常工作

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

我有一个打开Window的命令,并且该窗口创建ViewModel等等 - 在那里没什么奇怪的。

在那个Window我有一些RelayCommand ,例如:

CategoryBeenSelected = new RelayCommand(() => OnCategoryUpdate = true);

没有什么奇怪的 - 它按我的预期工作。

问题是我不能有一个通用的RelayCommand的CanExecute方法/ lambda表达式。

这工作:

DeleteCategoryCommand = new RelayCommand<int>(DeleteCategory);

但是这并不是:

DeleteCategoryCommand = new RelayCommand<int>(DeleteCategory, CanDeleteCategory);

该窗口不显示。 我的意思是,我点击打开窗口的按钮,应用程序刚刚被阻塞,几秒钟后,Window的InitializeComponent方法抛出一个NullReferenceException (对象引用未设置为对象的实例)

简而言之,如果我将一个CanExecute方法放在RelayCommand<T> ,则拥有该ViewModel的Window (以及RelayCommand<T> )不能实例化。 如果我删除了CanExecuteWindow就会出现。

问题在哪里? 我很困惑。

谢谢。

编辑:根据要求,这里是堆栈跟踪:

A first chance exception of type 'System.NullReferenceException' occurred in PresentationFramework.dll
   at GalaSoft.MvvmLight.Command.RelayCommand`1.CanExecute(Object parameter)
   at System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute()
   at System.Windows.Controls.Primitives.ButtonBase.OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs args)
   at System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex, DependencyProperty dp, PropertyMetadata metadata, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType)
   at System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp, Object value, PropertyMetadata metadata, Boolean coerceWithDeferredReference, Boolean coerceWithCurrentValue, OperationType operationType, Boolean isInternal)
   at System.Windows.DependencyObject.SetValue(DependencyProperty dp, Object value)
   at MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(Object inst, XamlMember property, Object value)
   at MS.Internal.Xaml.Runtime.PartialTrustTolerantRuntime.SetValue(Object obj, XamlMember property, Object value)
   at System.Xaml.XamlObjectWriter.Logic_ApplyPropertyValue(ObjectWriterContext ctx, XamlMember prop, Object value, Boolean onParent)
   at System.Xaml.XamlObjectWriter.Logic_DoAssignmentToParentProperty(ObjectWriterContext ctx)
   at System.Xaml.XamlObjectWriter.WriteEndObject()
   at System.Windows.Markup.WpfXamlLoader.TransformNodes(XamlReader xamlReader, XamlObjectWriter xamlWriter, Boolean onlyLoadOneNode, Boolean skipJournaledProperties, Boolean shouldPassLineNumberInfo, IXamlLineInfo xamlLineInfo, IXamlLineInfoConsumer xamlLineInfoConsumer, XamlContextStack`1 stack, IStyleConnector styleConnector)
   at System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader, IXamlObjectWriterFactory writerFactory, Boolean skipJournaledProperties, Object rootObject, XamlObjectWriterSettings settings, Uri baseUri)
   at System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader, Boolean skipJournaledProperties, Object rootObject, XamlAccessLevel accessLevel, Uri baseUri)
   at System.Windows.Markup.XamlReader.LoadBaml(Stream stream, ParserContext parserContext, Object parent, Boolean closeStream)
   at System.Windows.Application.LoadComponent(Object component, Uri resourceLocator)
   at ApuntaNotas.Views.CategoryEditorView.InitializeComponent() in c:UsersJesusDocumentsVisual Studio 2010ProjectsApuntaNotasApuntaNotasViewsCategoryEditorView.xaml:line 1
   at ApuntaNotas.Views.CategoryEditorView..ctor() in C:UsersJesusDocumentsVisual Studio 2010ProjectsApuntaNotasApuntaNotasViewsCategoryEditorView.xaml.cs:line 18
A first chance exception of type 'System.NullReferenceException' occurred in PresentationFramework.dll

看来RelayCommand会将参数的值转换为泛型T.

但是你不能将一个空值赋给一个结构体,正如异常告诉你的那样!

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

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

HTH


Arcturus在识别问题时是正确的,但我不喜欢使用可空基元的解决方案。 除非我有充分的理由使用它们,否则我个人不喜欢可空的基元。

相反,我改变了RelayCommand的实现,如下所示:

    bool ICommand.CanExecute(object parameter)
    {
        if (parameter == null && typeof(T).IsValueType)
        {
            return CanExecute(default(T));
        }
        return CanExecute((T)parameter);
    }

我没有为通用的Execute方法做出同样的改变(至少现在是这样),因为如果命令确实需要参数,我认为在这种情况下失败是不合理的。

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

        <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中,您注意到命令参数绑定到控件的实际宽度。 但是,在“imageScrollViewer”控件必须布置/呈现之前,WPF将在按钮的命令中调用CanExecute - 因此没有实际的宽度/高度。 当用户点击按钮并调用Execute时,当然控件已经布置好,所以值会被发送到命令中。 如果没有 - 我认为失败是应该预期的 - 但只有当用户实际点击按钮时。

当然,我不喜欢CanExecute和Execute的不同行为,但现在它似乎符合框架提出的限制。 我可能会发现这种情况导致我悲伤,但我一直喜欢这种变化。


也许,在这个时候,参数是null

链接地址: http://www.djcxy.com/p/30519.html

上一篇: CanExecute on RelayCommand<T> not working

下一篇: How to get the sizes of the tables of a MySQL database?