2010-06-24 13 views
18

यदि आप एमवीवीएम कर रहे हैं और कमांड का उपयोग कर रहे हैं, तो आप अक्सर व्यूमोडेल पर आईसीओएमएंड गुण देखेंगे जो निजी रिलेकॉमैंड या डेलेगेट कमांड फ़ील्ड द्वारा समर्थित हैं, इस उदाहरण की तरह मूल एमवीवीएम आलेख से MSDN:डब्ल्यूपीएफ एमवीवीएम में रिलेकॉमैंड/डिलीगेट कॉमांड को सरल बनाना

RelayCommand _saveCommand; 
public ICommand SaveCommand 
{ 
    get 
    { 
     if (_saveCommand == null) 
     { 
      _saveCommand = new RelayCommand(param => this.Save(), 
       param => this.CanSave); 
     } 
     return _saveCommand; 
    } 
} 

हालांकि, इस अव्यवस्था का एक बहुत है, और नहीं बल्कि थकाऊ (मैं कुछ अनुभवी WinForms डेवलपर्स जो यह सब टाइपिंग पर भी मुंह के साथ काम) नए आदेश की स्थापना करता है। तो मैं इसे सरल बनाना चाहता था और थोड़ा सा खोदना चाहता था। मैंने {} ब्लॉक प्राप्त करने की पहली पंक्ति में ब्रेकपॉइंट सेट किया और देखा कि जब मेरा ऐप पहली बार लोड किया गया था तो यह केवल हिट हो गया था - मैं बाद में जितना चाहूं उतने कमांड को बंद कर सकता हूं और यह ब्रेकपॉइंट कभी हिट नहीं होता है - इसलिए मैं इस सरल करने के लिए मेरी ViewModels से कुछ अव्यवस्था को दूर करना चाहता था और पाया है कि निम्नलिखित कोड एक ही काम करता है:

public ICommand SaveCommand 
{ 
    get 
    { 
     return new RelayCommand(param => this.Save(), param => this.CanSave); 
    } 
} 

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

उत्तर

8

मुझे पता चला कि आपको एमएसडीएन से मूल तरीके की आवश्यकता है यदि आपके पास एकाधिक नियंत्रण हैं जो समान आदेशों का आह्वान करते हैं, अन्यथा प्रत्येक नियंत्रण अपने स्वयं के रिले कॉमांड को नया करेगा। मुझे यह एहसास नहीं हुआ क्योंकि मेरे ऐप में केवल प्रति नियंत्रण एक नियंत्रण है।

तो व्यूमोडल्स में कोड को सरल बनाने के लिए, मैं एक कमांड रैपर क्लास तैयार करूंगा जो सभी रिलेकॉमैंड्स को स्टोर (और आलसी रूप से तत्काल) करता है और इसे मेरे व्यूमोडेलबेस क्लास में फेंक देता है। इस तरह से उपयोगकर्ताओं को सीधे RelayCommand या DelegateCommand वस्तुओं का दृष्टांत की जरूरत नहीं है और उनके बारे में कुछ भी जानने की जरूरत नहीं है:

/// <summary> 
    /// Wrapper for command objects, created for convenience to simplify ViewModel code 
    /// </summary> 
    /// <author>Ben Schoepke</author> 
    public class CommandWrapper 
    { 
    private readonly List<DelegateCommand<object>> _commands; // cache all commands as needed 

    /// <summary> 
    /// </summary> 
    public CommandWrapper() 
    { 
     _commands = new List<DelegateCommand<object>>(); 
    } 

    /// <summary> 
    /// Returns the ICommand object that contains the given delegates 
    /// </summary> 
    /// <param name="executeMethod">Defines the method to be called when the command is invoked</param> 
    /// <param name="canExecuteMethod">Defines the method that determines whether the command can execute in its current state. 
    /// Pass null if the command should always be executed.</param> 
    /// <returns>The ICommand object that contains the given delegates</returns> 
    /// <author>Ben Schoepke</author> 
    public ICommand GetCommand(Action<object> executeMethod, Predicate<object> canExecuteMethod) 
    { 
     // Search for command in list of commands 
     var command = (_commands.Where(
          cachedCommand => cachedCommand.ExecuteMethod.Equals(executeMethod) && 
              cachedCommand.CanExecuteMethod.Equals(canExecuteMethod))) 
              .FirstOrDefault(); 

     // If command is found, return it 
     if (command != null) 
     { 
      return command; 
     } 

     // If command is not found, add it to the list 
     command = new DelegateCommand<object>(executeMethod, canExecuteMethod); 
     _commands.Add(command); 
     return command; 
    } 
} 

इस वर्ग भी lazily ViewModelBase वर्ग द्वारा instantiated है, इसलिए किसी भी ViewModels आदेशों की जरूरत नहीं है कि अतिरिक्त आवंटन से बचेंगे।

+4

यदि आप वास्तव में अपने मेमोरी उपयोग के बारे में चिंतित हैं, तो क्या यह केवल उन आदेशों को तुरंत चालू करने के लिए समझ में नहीं आता है जिन्हें आप उपयोग करने जा रहे हैं? उदाहरण के लिए, यदि आपके पास एक वीएम है जो 3 कमांड का खुलासा करता है, और केवल एक का उपयोग किया जाता है, तो बाकी को छोड़ दें। यदि आप अपने सभी वीएम कमांड का उपयोग कर रहे हैं (जो आपको होना चाहिए), तो आलसी लोडिंग की आपकी प्रणाली अधिक मेमोरी और अधिक प्रोसेसर समय का उपयोग करेगी जो विशेष रूप से एम्बेडेड सिस्टम के लिए पहली जगह अनुकूलित करने के उद्देश्य को हरा देती है। –

7

एक चीज जो मैं करता हूं वह विजुअल स्टूडियो को मेरे लिए टाइपिंग करने देता है। मैं सिर्फ इतना है कि मुझे

rc टैब लिखकर RelayCommand बनाने की अनुमति देता के लिए कोड स्निपेट सहेजें दर्ज बनाई

rc कोड शॉर्टकट झलकी है टैब लिखे गए पाठ को आप क्या लोड हो जाता है चाहते हैं और यह सभी अन्य शब्द बनाता है।

तुम वापस :)

अधिक जानकारी के लिए कोड के टुकड़े बनाने पर कभी नहीं जाना होगा एक बार जब आप एक कोड स्निपेट को देखो और अपना खुद का बना: http://msdn.microsoft.com/en-us/library/ms165394.aspx

+1

मुझे नहीं पता कि किसी और ने इसका उल्लेख क्यों नहीं किया है। यह वही है जो मैं करता हूं और आदेशों के लिए बॉयलरप्लेट कोड को संभालने का सबसे अच्छा तरीका है। उस आलसी-> आलसी सामान वास्तव में लंबे समय तक किसी भी समय या कोड को बचा नहीं है। –

+0

अपने स्निपेट को साझा करने के लिए देखभाल? –

+1

यहां मेरा http://pastebin.com/YHD8AUjR –

17

यह बिल्कुल वैसा ही है जैसे कि आप की पेशकश करेगा ए - पूर्णांक कहें - संपत्ति जो कुछ निरंतर मान की गणना करती है। आप या तो गेट-विधि पर प्रत्येक कॉल के लिए इसकी गणना कर सकते हैं या आप बाद में कॉल के लिए कैश किए गए मान को वापस करने के लिए इसे पहले कॉल पर बना सकते हैं और फिर इसे कैश कर सकते हैं। तो यदि गेटटर को सबसे अधिक बार बुलाया जाता है, तो इसे कोई फर्क नहीं पड़ता है, अगर इसे अक्सर कहा जाता है, तो आप कुछ (अधिक नहीं) प्रदर्शन खो देंगे, लेकिन आपको वास्तविक परेशानी नहीं होगी।

RelayCommand _saveCommand; 
public ICommand SaveCommand 
{ 
    get 
    { 
    return _saveCommand ?? (_saveCommand = new RelayCommand(param => this.Save(), 
                  param => this.CanSave)); 
    } 
} 
+1

अच्छा कॉल है। मुझे नल कोलेस ऑपरेटर का उपयोग पसंद है। मैं हमेशा उस बारे में भूल जाता हूं। –

1

तुम सिर्फ क्यों नहीं लिखते:

मैं व्यक्तिगत रूप से MSDN तरह से इस तरह संक्षिप्त चाहते

private readonly RelayCommand _saveCommand = new RelayCommand(param => this.Save(), 
       param => this.CanSave);; 

public ICommand SaveCommand { get { return _saveCommand; } } 
+0

मुझे लगता है कि किसी ऑब्जेक्ट को बिना किसी आवश्यकता के निर्माण को रोकने के लिए है, लेकिन मुझे वास्तव में स्मृति का उपयोग करने या कमांड बनाने के अन्य दुष्प्रभावों को नहीं पता है ... – jpsstavares

+0

हम स्मृति को बचाने के लिए आलसी तत्काल चाहते थे। मैंने एक व्यूमोडेलबेस क्लास में कुछ कोड जोड़ना समाप्त कर दिया जो रिलेकॉमैंड्स की एक सूची <> स्टोर करता है और GetCommand() नामक एक विधि है। इसलिए जब हम व्यूमोडेल को कार्यान्वित करते हैं, तो हमें कमांड बनाने के लिए केवल एक आईसीओएमएंड संपत्ति बनाने की ज़रूरत होती है जो निष्पादन के साथ GetCommand() को कॉल करता है और प्रतिनिधियों को निष्पादित कर सकता है, और ViewModel कार्यान्वयनकर्ता को RelayCommand/Delegate कमांड के बारे में कुछ भी जानने की आवश्यकता नहीं है। –

+5

मैं कमांड को अनुकूलित करना शुरू नहीं करूंगा क्योंकि कमांड की मेमोरी पदचिह्न बहुत कम है। – jbe

0

जब आप अपने viewmodel पर ICommand संपत्ति का खुलासा और ऐसा नहीं एक बैकिंग फील्ड नहीं है, यह ठीक है, बस जब तक आप केवल इस क्षेत्र में बाध्य हों। असल में, जब आपका फॉर्म लोड होता है और यह प्रारंभिक बाइंडिंग करता है, तो यह केवल एकमात्र समय है जब यह आपके कमांड की संपत्ति तक पहुंचने जा रहा है।

कई बार ऐसे समय होते हैं जब आप केवल एक ही समय में बाध्य करेंगे।

यदि आप एक ही कमांड को एक से अधिक नियंत्रण में बाध्य करते हैं, तो आपको बैकिंग फ़ील्ड की आवश्यकता होगी।

1

जब आप अपने व्यूमोडेल पर आईसीओएमएंड संपत्ति का पर्दाफाश करते हैं और इसमें बैकिंग फ़ील्ड नहीं होता है, तो यह ठीक है, जब तक कि आप केवल एक बार इस क्षेत्र से जुड़ें।

कमांडवापर का GetCommand विधि कमांड को वापस कर देगा यदि यह पहले से बनाया गया है।