WPF - अपने CommandBindings के माध्यम से 'CanExecute' के पुनर्मूल्यांकन के लिए एक कमांड को कैसे बाध्य किया जाए


130

मेरे पास एक ऐसा स्थान है Menuजहां MenuItemपदानुक्रम में प्रत्येक ने अपनी Commandसंपत्ति को एक RoutedCommandपरिभाषित किया है। संबंधित CommandBindingमूल्यांकन के लिए एक कॉलबैक प्रदान करता है CanExecuteजो प्रत्येक की सक्षम स्थिति को नियंत्रित करता है MenuItem

यह लगभग काम करता है। मेनू आइटम शुरू में सही सक्षम और अक्षम राज्यों के साथ आते हैं। हालाँकि जब डेटा मेरे CanExecuteकॉलबैक में परिवर्तन का उपयोग करता है, तो मुझे इस नए राज्य के लिए UI में परिलक्षित होने के लिए अपने कॉलबैक से परिणाम का अनुरोध करने के लिए कमांड की आवश्यकता होती है।

इस पर RoutedCommandया इसके CommandBindingलिए कोई सार्वजनिक तरीका नहीं दिखता है ।

ध्यान दें कि कॉलबैक का उपयोग तब किया जाता है जब मैं क्लिक करता हूं या कंट्रोल में टाइप करता हूं (मुझे लगता है कि यह इनपुट पर चालू है क्योंकि माउस-ओवर रिफ्रेश का कारण नहीं बनता है)।

जवाबों:


172

पुस्तक में सबसे सुंदर नहीं है, लेकिन आप कमांड कमांडर का उपयोग सभी कमांडबाइंडिंग को अमान्य करने के लिए कर सकते हैं:

CommandManager.InvalidateRequerySuggested();

MSDN पर अधिक जानकारी देखें


1
धन्यवाद यह ठीक काम किया। UI में थोड़ी देरी है, लेकिन मैं इसके बारे में बहुत चिंतित नहीं हूं। इसके अलावा, मैंने आपके उत्तर को तुरंत वोट दिया, फिर वोट लिया कि क्या यह काम करता है। अब जबकि यह काम कर रहा है, मैं फिर से वोट को फिर से लागू नहीं कर सकता। निश्चित नहीं है कि एसओ के पास वह नियम क्यों है।
ड्रू नॉक

5
मैंने अपना मत पुनः प्राप्त करने के लिए आपके उत्तर को संपादित किया। मैंने संपादन में कुछ भी नहीं बदला। एक बार फिर धन्यवाद।
ड्रू नॉक

मुझे वही समस्या हो रही थी जब मैं कोड-पीछे से टेक्सबॉक्स की सामग्री को बदल रहा था। यदि आप इसे हाथ से संपादित करते हैं तो यह काम करेगा। इस ऐप में, उनके पास एक नियंत्रण द्वारा संपादित किया गया टेक्सबॉक्स था जिसे पॉपअप किया जाएगा, और जब आप पॉपअप को बचा लेते हैं, तो यह टेक्सबॉक्स को बदल देगा। इससे समस्या हल हो गई! धन्यवाद @Arcturus
डेज़ी

10
बस अन्य उत्तर से ध्यान दें ( stackoverflow.com/questions/783104/refresh-wpf-command ) "इसे यूआई थ्रेड पर कॉल करना होगा"
सेमवेल सिरेडेगन

84

किसी के लिए भी जो बाद में इस पार आता है; यदि आप एमवीवीएम और प्रिज्म का उपयोग कर रहे हैं, तो प्रिज्म का DelegateCommandकार्यान्वयन ऐसा करने के लिए ICommandएक .RaiseCanExecuteChanged()विधि प्रदान करता है ।


12
यह पैटर्न अन्य MVVM लाइब्रेरी में भी पाया जाता है, जैसे MVVM लाइट।
पीटर लिलवोल्ड

2
प्रिज्म के विपरीत, MVVM लाइट v5 का स्रोत कोड इसकी RaiseCanExecuteChanged() सरल कॉल को इंगित करता है CommandManager.InvalidateRequerySuggested()
पीटर

4
WPF में MVVM लाइट करने के लिए एक ओर ध्यान दें, आप GalaSoft.MvvmLight.Command के बाद से नाम स्थान GalaSoft.MvvmLight.CommandWpf उपयोग करने के लिए मुसीबत का कारण होगा जरूरत mvvmlight.net/installing/changes#v5_0_2
fuchs777

((RelayCommand)MyCommand).RaiseCanExecuteChanged();मेरे लिए काम किया, GalaSoft.MvvmLight.Command का उपयोग करते हुए - लेकिन बदलने के बाद CommandWPF, यह कुछ भी कॉल करने की आवश्यकता के बिना काम किया। धन्यवाद @ fuchs777
रॉबिन बेनेट

1
यदि आप एक 3 पार्टी पुस्तकालय का उपयोग नहीं कर रहे हैं, तो क्या होगा?
विदर्भ

28

मैं उपयोग नहीं कर सका CommandManager.InvalidateRequerySuggested();क्योंकि मैं प्रदर्शन हिट हो रहा था।

मैंने MVVM हेल्पर के प्रतिनिधि आदेश का उपयोग किया है , जो नीचे जैसा दिखता है (मैंने इसे हमारे req के लिए थोड़ा ट्विक किया है)। आपको command.RaiseCanExecuteChanged()वीएम से कॉल करना होगा

public event EventHandler CanExecuteChanged
{
    add
    {
        _internalCanExecuteChanged += value;
        CommandManager.RequerySuggested += value;
    }
    remove
    {
        _internalCanExecuteChanged -= value;
        CommandManager.RequerySuggested -= value;
    }
}

/// <summary>
/// This method can be used to raise the CanExecuteChanged handler.
/// This will force WPF to re-query the status of this command directly.
/// </summary>
public void RaiseCanExecuteChanged()
{
    if (canExecute != null)
        OnCanExecuteChanged();
}

/// <summary>
/// This method is used to walk the delegate chain and well WPF that
/// our command execution status has changed.
/// </summary>
protected virtual void OnCanExecuteChanged()
{
    EventHandler eCanExecuteChanged = _internalCanExecuteChanged;
    if (eCanExecuteChanged != null)
        eCanExecuteChanged(this, EventArgs.Empty);
}

3
केवल एक FYI करें मैंने कमांड मैनजर पर टिप्पणी की। RequerySuggested + = value; मुझे किसी कारण से अपने CanExecute कोड का निरंतर / लूपिंग मूल्यांकन मिल रहा था। अन्यथा समाधान ने अपेक्षा के अनुरूप काम किया। धन्यवाद!
रोबौदास

15

यदि आपने अपनी स्वयं की कक्षा को लुढ़का दिया है, तो आप ICommandबहुत अधिक स्वचालित स्टेटस अपडेट खो सकते हैं, जिससे आपको मैनुअल रीफ्रेशिंग पर भरोसा करने की जरूरत होती है। यह टूट भी सकता है InvalidateRequerySuggested()। समस्या यह है कि एक सरल ICommandकार्यान्वयन नए कमांड को लिंक करने में विफल रहता है CommandManager

समाधान निम्नलिखित का उपयोग करना है:

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void RaiseCanExecuteChanged()
    {
        CommandManager.InvalidateRequerySuggested();
    }

इस तरह ग्राहक CommandManagerआपकी कक्षा के बजाय संलग्न होते हैं और कमांड स्थिति परिवर्तनों में ठीक से भाग ले सकते हैं।


2
सीधे, बात करने के लिए, और लोगों को अपने ICommand कार्यान्वयन पर नियंत्रण करने की अनुमति देता है।
एकोई Meexx

2

मैंने कमांड पर संपत्ति निर्भरता को संभालने के लिए एक समाधान लागू किया है, यहां लिंक https://stackoverflow.com/a/30394333/16162020

इसके लिए धन्यवाद कि आप इस तरह से एक कमांड करेंगे:

this.SaveCommand = new MyDelegateCommand<MyViewModel>(this,
    //execute
    () => {
      Console.Write("EXECUTED");
    },
    //can execute
    () => {
      Console.Write("Checking Validity");
       return PropertyX!=null && PropertyY!=null && PropertyY.Length < 5;
    },
    //properties to watch
    (p) => new { p.PropertyX, p.PropertyY }
 );

-3

यह मेरे लिए काम किया है: XAML में कमांड से पहले CanExecute रखो।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.