Question

J'écris un WPF 4 app (avec VS2010 RC) en utilisant MVVM lumière V3 alpha 3 et je suis en cours d'exécution dans un comportement bizarre ici ...

J'ai une commande qui ouvre une Window, et que la fenêtre crée ViewModel et ainsi de suite -. Rien bizarre là-bas

Dans ce Window j'ai quelques RelayCommands, par exemple:

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

Rien de nouveau bizarre - cela fonctionne comme je m'y attendais

.

Le problème est que je ne peux pas avoir une expression méthode CanExecute / lambda avec un RelayCommand générique.

Cela fonctionne:

DeleteCategoryCommand = new RelayCommand<int>(DeleteCategory);

Mais cela ne fait pas:

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

La fenêtre ne se présente pas. Je veux dire, je clique sur le bouton qui ouvre la fenêtre, et l'application devient juste bloqué et quelques secondes plus tard, la méthode de InitializeComponent de la fenêtre jette un NullReferenceException (référence d'objet non définie à une instance d'un objet)

En bref, si je mets une méthode de CanExecute sur un RelayCommand<T>, le Window que est propriétaire qui ViewModel (avec le RelayCommand<T>) ne peut pas être instancié. Si je retire le CanExecute, le Window apparaît.

Où est le problème ici? Je suis confus.

Merci.

EDIT: Comme l'a demandé, voici la trace de la pile:

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
Était-ce utile?

La solution

Il semble que le RelayCommand chassera la valeur du paramètre à T. générique

Mais vous ne pouvez pas jeter un nul à un struct, comme l'exception vous dit!

Si vous initialisez le RelayCommand avec une struct annulable, il fonctionnera comme prévu!

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

HTH

Autres conseils

Arcturus a correctement identifié ce problème mais le était, je ne l'ai pas aimé la solution d'utiliser les primitives nullables. Personnellement, je n'aime pas primitives nullables à moins d'avoir une très bonne raison de les utiliser.

Au lieu de cela, je l'ai changé la mise en œuvre de RelayCommand comme suit:

    bool ICommand.CanExecute(object parameter)
    {
        if (parameter == null && typeof(T).IsValueType)
        {
            return CanExecute(default(T));
        }
        return CanExecute((T)parameter);
    }

Je ne faisais pas ce même changement pour la méthode générique d'exécution (au moins pour l'instant) parce que je ne pense pas qu'il est déraisonnable d'échouer dans ce cas, si la commande n'attend vraiment un argument.

Le problème avec CanExecute est que le système WPF appelle quelquefois avant certaines liaisons peuvent être évaluées. Par exemple:

        <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}" />

Dans le XAML ci-dessus, on remarque le paramètre de commande est lié à la largeur réelle d'un contrôle. Cependant, WPF appellera CanExecute sur la commande du bouton avant la commande « imageScrollViewer » est nécessairement aménagé / rendu - donc il n'y a pas de largeur réelle / hauteur. Au moment où l'utilisateur clique sur le bouton et d'exécution est invoquée, bien sûr, le contrôle est aménagé de façon valeurs sont envoyés à la commande. Dans le cas contraire - je pense ne pas est ce qu'il faut attendre -. Mais seulement lorsque l'utilisateur clique réellement sur le bouton

Bien sûr, je n'aime pas le comportement différent des CanExecute et exécutons, mais pour l'instant il semble tenir dans les limites présentées par le cadre. Je trouve un scénario où cela me cause la douleur, mais j'ai goût le changement à ce jour.

Peut-être, à ce moment, le paramètre est null?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top