2010-02-21 38 views
11

我正在寫使用MVVM光V3阿爾法3 WPF應用程序4(與VS2010 RC)和正在運行到這裏的一些怪異的行爲...CanExecute上RelayCommand <T>不工作

我打開一個命令Window,並且該窗口創建ViewModel等 - 沒有什麼奇怪的。再次

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

沒什麼奇怪的 - 它的工作原理如我所料:

在這種Window我有一些RelayCommand S,例如。

問題是我不能有一個通用的RelayCommand CanExecute方法/ lambda表達式。

這工作:

DeleteCategoryCommand = new RelayCommand<int>(DeleteCategory); 

但這並不:

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

窗口不顯示。我的意思是,我點擊打開窗口的按鈕,應用程序就被阻止,幾秒鐘後,窗口的InitializeComponent方法拋出一個NullReferenceException(對象引用未設置爲對象的實例)

總之,如果我把CanExecute方法放在RelayCommand<T>,Window擁有那ViewModel(與RelayCommand<T>)不能實例化。如果我刪除CanExecute,則顯示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 
+1

也許你可以附加一個堆棧跟蹤?這可能有助於瞭解哪裏出了問題。 – Vlad

+0

對不起,我忘記了,它是:) –

+0

這很奇怪:反射器告訴函數'CanExecute'是這樣定義的:'public bool CanExecute(object parameter){return(this._canExecute == null)| | this._canExecute((T)parameter)); }'。沒有什麼可以拋出異常。 – Vlad

回答

7

看來,RelayCommand將參數強制轉換值一般T.

但是你不能投一個空的結構,作爲異常告訴你!

如果使用可空結構初始化RelayCommand,它將按預期工作!

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

HTH

+0

嗯,這應該是原因...但它有點奇怪..我沒有看到任何代碼使用可爲空...... –

+0

是的,這是正確的..'double'或'int'是值類型,不能爲空。如果你讓它們爲可空類型,它應該工作。將'null'投射到一個結構將產生一個異常!請參閱Vlads評論的方法,您可以將演員視爲T! – Arcturus

+0

嘗試編譯double test =(double)null;在通用世界中,您將獲得運行時異常! ;) – Arcturus

0

也許,在這個時候,參數是null

2

大角星是在弄清問題是什麼是正確的,但我不喜歡使用可空原語的解決方案。除非我有充分的理由使用它們,否則我個人不喜歡可空的基元。

相反,我改變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的不同行爲,但現在它似乎符合框架提出的限制。我可能會發現這種情況導致我悲傷,但我一直喜歡這種變化。

相關問題