2012-10-04 15 views
10

पर कॉल में फ़ील्ड वैरिएबल पर कैप्चर करना क्यों है, मैं हाल ही में लैम्ब्डा अभिव्यक्ति और परिवर्तनीय कैप्चर के साथ एक अजीब चीज से थोड़ा सा था। कोड .NET 4.5 (VS2012) का उपयोग कर एक WPF/MVVM एप्लिकेशन था।मुझे लैम्ब्डा को कन्स्ट्रक्टर

public class MyViewModel : ViewModelBase 
{ 
    public MyViewModel(Action menuCallback) 
    { 
     MyCommand = new RelayCommand(menuCallback); 
    } 

    public MyViewModel(Func<ViewModelBase> viewModelCreator) 
    // I also tried calling the other constructor, but the result was the same 
    // : this(() => SetMainContent(viewModelCreator()) 
    { 
     Action action =() => SetMainContent(viewModelCreator()); 
     MyCommand = new RelayCommand(action); 
    } 

    public ICommand MyCommand { get; private set; } 
} 

: मैं अपने viewmodel के विभिन्न निर्माताओं सेटअप करने के लिए एक RelayCommand के लिए कॉलबैक उपयोग कर रहा था (यह आदेश तो मेरे विचार में एक मेनू आइटम करने के लिए बाध्य किया जाता था)

संक्षेप में, मैं निम्नलिखित कोड था और उसके बाद का उपयोग करके उपरोक्त के उदाहरण बनाया:

// From some other viewmodel's code: 
new MyViewModel(() => new SomeViewModel()); 
new MyViewModel(() => new SomeOtherViewModel()); 

ये तो एक WPF मेनू करने के लिए बाध्य कर रहे थे - प्रत्येक मेनू आइटम अपने डेटा संदर्भ के रूप में एक MyViewModel उदाहरण था। अजीब चीज यह थी कि मेनू केवल एक बार काम करता था। चाहे मैंने कोशिश की वस्तुओं में से कोई भी, यह उपयुक्त Func<ViewModelBase> - लेकिन केवल एक बार कॉल करेगा। अगर मैंने एक और मेनू आइटम या फिर भी वही आइटम चुनने का प्रयास किया, तो यह काम नहीं करता है। किसी भी त्रुटि के बारे में वीएस डीबग आउटपुट में कुछ भी नहीं कहा गया और कोई आउटपुट नहीं मिला।

मैं छोरों में चर कैप्चर के मुद्दे से परिचित हूँ, इसलिए मैं एक अनुमान है कि इस मुद्दे को संबंधित था बनाया तो मेरी वी एम के लिए बदल दिया:

public class MyViewModel : ViewModelBase 
{ 
    public MyViewModel(Action buttonCallback) 
    { 
     MyCommand = new RelayCommand(buttonCallback); 
    } 
    private Func<ViewModelBase> _creator; 
    public MyViewModel(Func<ViewModelBase> viewModelCreator) 
    { 
     // Store the Func<> to a field and use that in the Action lambda 
     _creator = viewModelCreator; 
     var action =() => SetMainContent(_creator()); 
     MyCommand = new RelayCommand(action); 
    } 

    public ICommand MyCommand { get; private set; } 
} 

और उसी तरह यह कहा जाता है। अब सबकुछ काम करता है जैसा इसे करना चाहिए।

बस मस्ती के लिए, मैं भी पूरे Func<ViewModelBase> निर्माता के आसपास MyViewModel निर्माता की उचित Action बाहर बनाने के द्वारा काम किया:

// This code also works, even without the _creator field in MyViewModel 
new MyViewModel(() => SetMainContent(new SomeViewModel())); 
new MyViewModel(() => SetMainContent(new SomeOtherViewModel())); 

तो मैं यह काम कर रहा करने के लिए कामयाब रहे, लेकिन मैं अभी भी उत्सुक हूँ क्यों यह इस तरह काम करता है। कंपाइलर कन्स्ट्रक्टर में Func<ViewModelBase> को सही तरीके से कैप्चर नहीं करता है?

+1

क्या आपने दो दृष्टिकोणों के लिए उत्पन्न आईएल में मतभेदों को देखा है? यह कुछ संकेत दे सकता है। – nicodemus13

+0

यदि 'SetMainContent'' ViewModelBase' वर्ग में है, तो आप इसे अपने अंतिम कोड उदाहरण में लैम्ब्डा में कैसे कॉल कर रहे हैं जो काम करता है? – Pat

+0

SetMainContent मुख्य विंडो के व्यूमोडेल में व्यूमोडेल उदाहरण भेजने के लिए संदेशों (एमवीवीएमएल से) का उपयोग करता है। इसके बाद इसे एक सामग्री प्रॉपर्टी को असाइन किया जाएगा जो यूआई में प्रस्तुत किया जाता है। मैं एक और पूर्ण कोड उदाहरण के साथ आने का प्रयास करूंगा जो इस मुद्दे को प्रदर्शित करता है –

उत्तर

2

मेरा अनुमान है कि निम्नलिखित कोड भी काम करेगा

public MyViewModel(Func<ViewModelBase> viewModelCreator) 
{ 
    var action =() => { creator = viewModelCreator; SetMainContent(creator()); }; 
    MyCommand = new RelayCommand(action); 
} 

यदि हां, तो कारण यह पहला तरीका काम नहीं कर रहा है कि आप वास्तव में viewModelCreator चर तक बंद नहीं कर रहे हैं है, तो आप ' इसे कॉल करने के परिणाम के आसपास बंद कर रहे हैं।

मैं अभी भी LINQPad में कोड के साथ खेल रहा हूं, लेकिन ऐसा नहीं लगता है कि मुझे वही समस्या मिल रही है जो आप हैं। शायद यह RelayCommand के लिए विशिष्ट है। क्या आप अपना अधिक कोड पोस्ट कर सकते हैं?

+0

उत्तर के लिए धन्यवाद। रिलेकॉमैंड एमवीवीएम लाइट से है: http://bit.ly/QRLCES –

+1

हम्म .. अपने स्वयं के प्रश्न से कोड का उपयोग करके इसे किसी अन्य कंप्यूटर (वीएस -2010 का उपयोग करके) पर पुन: पेश करने का प्रयास कर रहा हूं लेकिन मुझे यह नहीं दिख रहा है .. मुझे जाने की ज़रूरत है मेरे मूल कोड पर वापस जाएं और देखें कि अंतर क्या है (मेरा प्रश्न कोड सरलीकृत है - और यह हो सकता है कि मैंने बहुत सरल बनाया, और प्रक्रिया में समस्या को हटा दिया) –