relaycommand で動作していないことをcanexecuteします
-
21-09-2019 - |
質問
MVVM Light V3 Alpha 3を使用してWPF 4アプリ(VS2010 RCを使用)を書いており、ここで奇妙な動作に遭遇しています...
私はaを開くコマンドを持っています Window
, 、そしてそのウィンドウはビューモデルなどを作成します - そこに奇妙なことはありません。
その中で Window
いくつかあります RelayCommand
s、例:
CategoryBeenSelected = new RelayCommand(() => OnCategoryUpdate = true);
再び奇妙なことは何もありません - それは私が期待したように機能します。
問題は、一般的なリレーコマンドを使用してCanexecuteメソッド /ラムダ式を持たないことです。
これは機能します:
DeleteCategoryCommand = new RelayCommand<int>(DeleteCategory);
しかし、これは次のとおりです。
DeleteCategoryCommand = new RelayCommand<int>(DeleteCategory, CanDeleteCategory);
ウィンドウが表示されません。つまり、ウィンドウを開くボタンをクリックすると、アプリがブロックされ、数秒後にウィンドウがブロックされます。 InitializeComponent
メソッドスローa NullReferenceException
(オブジェクト参照がオブジェクト インスタンスに設定されていません)
要するに、私が置くと CanExecute
aのメソッド 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
解決
リレーコマンドは、値を汎用Tに値にキャストするようです。
ただし、例外が示すように、構造体にヌルをキャストすることはできません!
nullable構造体でリレーコマンドを初期化すると、予想どおりに機能します!
RelayCommand<int?> or RelayCommand<Nullable<int>>
Hth
他のヒント
Arcturusは、問題が何であるかを特定するのが正しかったが、ヌル可能なプリミティブを使用する解決策は気に入らなかった。私は個人的には、それらを使用する非常に正当な理由がない限り、邪魔なプリミティブが好きではありません。
代わりに、次のようにリレーコマンドの実装を変更しました。
bool ICommand.CanExecute(object parameter)
{
if (parameter == null && typeof(T).IsValueType)
{
return CanExecute(default(T));
}
return CanExecute((T)parameter);
}
コマンドが実際に議論を期待している場合、その場合に失敗することは不合理ではないと思うので、私は(少なくとも今のところ)一般的な実行方法でこれと同じ変更を加えませんでした。
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を呼び出します。したがって、実際の幅/高さはありません。ユーザーがボタンをクリックして実行される頃には、もちろんコントロールがレイアウトされるため、値がコマンドに送信されます。そうでない場合 - 私は失敗することが予想されるべきことだと思います - しかし、ユーザーが実際にボタンをクリックしたときのみです。
もちろん、私はCanexecuteと実行の異なる動作が好きではありませんが、今のところはフレームワークによって提示された制限に適合しているようです。私はこれが私に悲しみを引き起こすシナリオを見つけるかもしれませんが、私はこれまでの変化を好んでいました。
たぶん、この時点で、パラメーターはそうです null
?