Frage

Ich schreibe eine WPF 4 -App (mit VS2010 RC) unter Verwendung von MVVM Light V3 Alpha 3 und bin hier auf ein seltsames Verhalten ...

Ich habe einen Befehl, der a öffnet Window, Und dieses Fenster schafft das ViewModel und so weiter - nichts Seltsames dort.

Darin Window Ich habe welche RelayCommands, zum Beispiel:

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

Wieder nichts Seltsames - es funktioniert wie ich erwartet hatte.

Das Problem ist, dass ich keine CaneExecute -Methode / Lambda -Ausdruck mit einem generischen Relaycommand haben kann.

Das funktioniert:

DeleteCategoryCommand = new RelayCommand<int>(DeleteCategory);

Aber das tut nicht:

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

Das Fenster wird nicht angezeigt. Ich meine, ich klicke auf die Schaltfläche, die das Fenster öffnet, und die App wird nur blockiert und einige Sekunden später das Fenster des Fensters InitializeComponent Methode wirft a NullReferenceException (Der Objektverweis wurde nicht auf eine Instanz eines Objekts festgelegt)

Kurz gesagt, wenn ich eine lege CanExecute Methode auf a RelayCommand<T>, das Window das besitzt Das ViewModel (mit dem RelayCommand<T>) kann nicht instanziiert werden. Wenn ich das entferne CanExecute, das Window auftaucht.

Wo ist das Problem hier? Ich bin verwirrt.

Vielen Dank.

Bearbeiten: Wie gewünscht ist hier die Stapelspur:

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
War es hilfreich?

Lösung

Es scheint, dass der Relaycommand den Wert den Parameter auf den generischen T übertragen wird.

Aber Sie können keine Null auf eine Struktur geben, wie die Ausnahme Ihnen sagt!

Wenn Sie das Relaycommand mit einer nullbaren Struktur initialisieren, funktioniert es wie erwartet!

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

HTH

Andere Tipps

Arcturus war zu Recht festgestellt, was das Problem war, aber mir gefiel die Lösung, nullbare Primitive zu verwenden. Ich persönlich mag keine nullbaren Primitiven, es sei denn, ich habe einen sehr guten Grund, sie zu verwenden.

Stattdessen habe ich die Implementierung von RelayCommand wie folgt geändert:

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

Ich habe die gleiche Änderung für die generische Ausführungsmethode (zumindest vorerst) nicht vorgenommen, weil ich nicht denke, dass es unangemessen ist, in diesem Fall zu scheitern, wenn der Befehl wirklich ein Argument erwartet.

Das Problem mit CaneExecute ist, dass das WPF -System es manchmal aufruft, bevor bestimmte Bindungen bewertet werden können. Zum Beispiel:

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

Im obigen XAML bemerken Sie, dass der Befehlsparameter an die tatsächliche Breite eines Steuerelements gebunden ist. WPF ruft CaneExecute jedoch auf dem Befehl der Schaltfläche auf, bevor das Steuerelement "ImagesCrollviewer" notwendigerweise angelegt/gerendert wird - daher gibt es keine tatsächliche Breite/Höhe. Wenn der Benutzer auf die Schaltfläche klickt und ausgeführt wird, wird natürlich das Steuerelement festgelegt, sodass die Werte an den Befehl gesendet werden. Wenn nicht - ich denke, fehlschlägt das, was zu erwarten ist - aber nur, wenn der Benutzer tatsächlich auf die Schaltfläche klickt.

Natürlich mag ich das unterschiedliche Verhalten von CaneExecute und Ausführung nicht, aber im Moment scheint es in die im Rahmen dargestellten Einschränkungen zu passen. Ich kann ein Szenario finden, in dem mir das Trauer verursacht, aber ich mochte die Veränderung bisher.

Vielleicht ist der Parameter zu diesem Zeitpunkt zu diesem Zeitpunkt null?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top