2010-02-21 8 views
11

मैं एक WPF 4 एप्लिकेशन (VS2010 आर सी) के साथ MVVM लाइट वी 3 अल्फा 3 का उपयोग लिख रहा हूँ और कुछ अजीब व्यवहार यहाँ में चल रहा हूँ ...CanExecute RelayCommand <T> पर काम नहीं कर

मैं एक कमांड एक खुलती है Window, और वह विंडो ViewModel बनाता है और इसी तरह - वहां कुछ भी अजीब नहीं है। फिर

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

कुछ भी नहीं अजीब - यह काम करता है के रूप में मैं उम्मीद:

कि Window में मैं उदाहरण के लिए कुछ RelayCommand रों है,।

समस्या यह है कि मेरे पास एक सामान्य रिलेकॉमैंड के साथ CanExecute विधि/लैम्ब्डा अभिव्यक्ति नहीं हो सकती है।

यह काम करता है:

DeleteCategoryCommand = new RelayCommand<int>(DeleteCategory); 

लेकिन यह नहीं करता है:

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

विंडो दिखाई नहीं देता है। मेरा मतलब है, मैं बटन खुलने वाली विंडो क्लिक करें, और एप्लिकेशन सिर्फ अवरुद्ध हो जाता है और कुछ सेकंड बाद, खिड़की के InitializeComponent विधि

संक्षेप में, अगर एक NullReferenceException (एक वस्तु का एक उदाहरण के लिए सेट नहीं ऑब्जेक्ट संदर्भ) फेंकता मैंने 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' फ़ंक्शन को इस तरह से परिभाषित किया गया है:' सार्वजनिक बूल CanExecute (ऑब्जेक्ट पैरामीटर) {वापसी (this._canExecute == null) | | this._canExecute ((टी) पैरामीटर)); } '। अपवाद फेंकने के लिए कुछ भी नहीं है। – Vlad

उत्तर

7

ऐसा लगता है कि RelayCommand सामान्य टी

के लिए मूल्य पैरामीटर डाली होगा लेकिन अगर आप एक struct करने के लिए एक अशक्त डाली नहीं कर सकते हैं, के रूप में अपवाद आपको बताता है!

यदि आप रिलेकॉमैंड को एक नालीदार संरचना के साथ प्रारंभ करते हैं, तो यह अपेक्षा के अनुसार काम करेगा!

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

HTH

+0

उम, यह कारण होना चाहिए ... लेकिन यह थोड़ा अजीब है .. मुझे शून्य कोड का उपयोग करके कोई कोड नहीं मिला ... –

+0

हां यह सही है .. एक 'डबल' या 'int' मूल्य प्रकार हैं, और शून्य नहीं हो सकता है। यदि आप उन्हें कमजोर प्रकार बनाते हैं, तो इसे काम करना चाहिए। एक संरचना में 'शून्य' कास्टिंग अपवाद पैदा करेगा! विधि के साथ Vlads टिप्पणी देखें जहां आप टी को कास्ट देख सकते हैं! – Arcturus

+0

डबल टेस्ट = (डबल) नल संकलित करने का प्रयास करें; सामान्य दुनिया में आपको रनटाइम अपवाद मिलेगा! ;) – Arcturus

0

हो सकता है, इस समय, पैरामीटर null है: जैसा कि अनुरोध किया है, यहाँ स्टैक ट्रेस है?

2

आर्कटुरस की पहचान क्या समस्या थी में सही था, लेकिन मैं नल पुरातन का उपयोग करने का समाधान पसंद नहीं आया। मैं व्यक्तिगत रूप से नामुमकिन प्राइमेटिव पसंद नहीं करता जब तक कि मेरे पास उनका उपयोग करने का बहुत अच्छा कारण न हो।

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

मैं सामान्य निष्पादित विधि (कम से कम अब के लिए) के लिए यह एक ही बदलाव नहीं किया है क्योंकि मुझे नहीं लगता कि यह अनुचित है है:

इसके बजाय, मैं RelayCommand के कार्यान्वयन के रूप में निम्नानुसार बदल उस मामले में असफल होने के लिए अगर आदेश वास्तव में एक तर्क की उम्मीद करता है।

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 को कॉल करेगा - इसलिए कोई वास्तविक चौड़ाई/ऊंचाई नहीं है। जब तक उपयोगकर्ता बटन क्लिक करता है और निष्पादन लागू होता है, निश्चित रूप से नियंत्रण निर्धारित किया जाता है ताकि मूल्य कमांड को भेजा जा सके। यदि नहीं - मुझे लगता है कि असफल होने की अपेक्षा की जानी चाहिए - लेकिन केवल तभी जब उपयोगकर्ता वास्तव में बटन पर क्लिक करता है।

बेशक मुझे CanExecute और निष्पादन के विभिन्न व्यवहार पसंद नहीं हैं, लेकिन अब यह ढांचे द्वारा प्रस्तुत प्रतिबंधों के भीतर फिट होना प्रतीत होता है। मुझे एक परिदृश्य मिल सकता है जहां इससे मुझे दुःख होता है, लेकिन मुझे अब तक बदलाव पसंद आया है।