[英]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
無法實例化。 如果我刪除了CanExecute
, 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
看來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.