簡體   English   中英

ReExCommand <T>上的CanExecute無法正常工作

[英]CanExecute on RelayCommand<T> not working

我正在使用MVVM Light V3 alpha 3編寫一個WPF 4應用程序(使用VS2010 RC),並且在這里遇到了一些奇怪的行為......

我有一個打開一個Window的命令,那個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 (對象引用未設置為對象的實例)

簡而言之,如果我在RelayCommand<T>上放置一個CanExecute方法,那么擁有該ViewModel(帶有RelayCommand<T> )的Window無法實例化。 如果我刪除了CanExecuteCanExecute顯示Window

這里的問題在哪里? 我糊塗了。

謝謝。

編輯:根據要求,這是堆棧跟蹤:

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:\Users\Jesus\Documents\Visual Studio 2010\Projects\ApuntaNotas\ApuntaNotas\Views\CategoryEditorView.xaml:line 1
   at ApuntaNotas.Views.CategoryEditorView..ctor() in C:\Users\Jesus\Documents\Visual Studio 2010\Projects\ApuntaNotas\ApuntaNotas\Views\CategoryEditorView.xaml.cs:line 18
A first chance exception of type 'System.NullReferenceException' occurred in PresentationFramework.dll

看來RelayCommand會將參數的值轉換為泛型T.

但是你不能將null轉換為結構,因為異常告訴你!

如果使用可為空的結構初始化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中,您注意到command參數綁定到控件的實際寬度。 但是,在“imageScrollViewer”控件必須布局/渲染之前,WPF將在按鈕的命令上調用CanExecute - 因此沒有實際的寬度/高度。 當用戶單擊按鈕並調用Execute時,控件的布局當然會將值發送到命令。 如果不是 - 我認為失敗是應該期待的 - 但僅當用戶實際點擊按鈕時。

當然我不喜歡CanExecute和Execute的不同行為,但是現在它似乎符合框架提出的限制。 我可能會發現這會讓我感到悲傷,但我一直都喜歡這種改變。

也許,此時參數為null

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM