11

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

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

在那Window我有一些RelayCommands,例如:

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

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

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

这有效:

DeleteCategoryCommand = new RelayCommand<int>(DeleteCategory);

但这不会:

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

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

简而言之,如果我将CanExecuteMethod 放在 a 上RelayCommand<T>,则Window拥有ViewModel(带有RelayCommand<T>)的 the 将无法实例化。如果我删除CanExecuteWindow就会出现。

这里的问题在哪里?我很困惑。

谢谢你。

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

PresentationFramework.dll 中出现“System.NullReferenceException”类型的第一次机会异常
   在 GalaSoft.MvvmLight.Command.RelayCommand`1.CanExecute(对象参数)
   在 System.Windows.Controls.Primitives.ButtonBase.UpdateCanExecute()
   在 System.Windows.Controls.Primitives.ButtonBase.OnCommandChanged(DependencyObject d,DependencyPropertyChangedEventArgs e)
   在 System.Windows.DependencyObject.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   在 System.Windows.FrameworkElement.OnPropertyChanged(DependencyPropertyChangedEventArgs e)
   在 System.Windows.DependencyObject.NotifyPropertyChange(DependencyPropertyChangedEventArgs 参数)
   在 System.Windows.DependencyObject.UpdateEffectiveValue(EntryIndex entryIndex、DependencyProperty dp、PropertyMetadata 元数据、EffectiveValueEntry oldEntry、EffectiveValueEntry& newEntry、布尔 coerceWithDeferredReference、布尔 coerceWithCurrentValue、OperationType operationType)
   在 System.Windows.DependencyObject.SetValueCommon(DependencyProperty dp、对象值、PropertyMetadata 元数据、布尔 coerceWithDeferredReference、布尔 coerceWithCurrentValue、OperationType operationType、布尔 isInternal)
   在 System.Windows.DependencyObject.SetValue(DependencyProperty dp,对象值)
   在 MS.Internal.Xaml.Runtime.ClrObjectRuntime.SetValue(对象实例,XamlMember 属性,对象值)
   在 MS.Internal.Xaml.Runtime.PartialTrustTolerantRuntime.SetValue(对象 obj,XamlMember 属性,对象值)
   在 System.Xaml.XamlObjectWriter.Logic_ApplyPropertyValue(ObjectWriterContext ctx,XamlMember 道具,对象值,布尔 onParent)
   在 System.Xaml.XamlObjectWriter.Logic_DoAssignmentToParentProperty(ObjectWriterContext ctx)
   在 System.Xaml.XamlObjectWriter.WriteEndObject()
   在 System.Windows.Markup.WpfXamlLoader.TransformNodes(XamlReader xamlReader、XamlObjectWriter xamlWriter、Boolean onlyLoadOneNode、Boolean skipJournaledProperties、Boolean shouldPassLineNumberInfo、IXamlLineInfo xamlLineInfo、IXamlLineInfoConsumer xamlLineInfoConsumer、XamlContextStack`1 堆栈、IStyleConnector styleConnector)
   在 System.Windows.Markup.WpfXamlLoader.Load(XamlReader xamlReader,IXamlObjectWriterFactory writerFactory,布尔型 skipJournaledProperties,对象 rootObject,XamlObjectWriterSettings 设置,Uri baseUri)
   在 System.Windows.Markup.WpfXamlLoader.LoadBaml(XamlReader xamlReader,布尔 skipJournaledProperties,对象 rootObject,XamlAccessLevel accessLevel,Uri baseUri)
   在 System.Windows.Markup.XamlReader.LoadBaml(流流,ParserContext parserContext,对象父,布尔 closeStream)
   在 System.Windows.Application.LoadComponent(对象组件,Uri 资源定位器)
   在 ApuntaNotas.Views.CategoryEditorView.InitializeComponent() 在 c:\Users\Jesus\Documents\Visual Studio 2010\Projects\ApuntaNotas\ApuntaNotas\Views\CategoryEditorView.xaml:line 1
   在 ApuntaNotas.Views.CategoryEditorView..ctor() 在 C:\Users\Jesus\Documents\Visual Studio 2010\Projects\ApuntaNotas\ApuntaNotas\Views\CategoryEditorView.xaml.cs:line 18
PresentationFramework.dll 中出现“System.NullReferenceException”类型的第一次机会异常
4

4 回答 4

7

似乎 RelayCommand 会将参数的值转换为通用 T。

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

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

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

高温高压

于 2010-02-23T16:34:44.140 回答
2

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

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

于 2011-02-23T18:41:41.680 回答
1

派对迟到了,但我一直在摸不着头脑,问题是我导入了错误的命名空间。

我应该进口:

using GalaSoft.MvvmLight.CommandWpf;

但我已经进口了:

using GalaSoft.MvvmLight.Command;.

希望这对某人有帮助!

于 2019-10-08T13:38:42.720 回答
0

也许,此时,参数是null

于 2010-02-22T00:21:49.163 回答