WPF CommandParameter NULL पहली बार CanExecute कहलाता है


86

मैंने WPF और कमांड्स के साथ एक समस्या में भाग लिया है जो कि एक ItemControl के DataTemplate के अंदर एक बटन से बंधा है। परिदृश्य काफी आगे है। आइटम्सकंट्रोल वस्तुओं की एक सूची से जुड़ा हुआ है, और मैं एक बटन पर क्लिक करके सूची में प्रत्येक वस्तु को हटाने में सक्षम होना चाहता हूं। बटन एक कमांड निष्पादित करता है, और कमांड डिलीट होने का ख्याल रखता है। CommandParameter उस ऑब्जेक्ट के लिए बाध्य है जिसे मैं हटाना चाहता हूं। इस तरह से मुझे पता है कि उपयोगकर्ता ने क्या क्लिक किया। एक उपयोगकर्ता को केवल अपनी "स्वयं" ऑब्जेक्ट को हटाने में सक्षम होना चाहिए - इसलिए मुझे यह सत्यापित करने के लिए कमांड के "CanExecute" कॉल में कुछ जांच करने की आवश्यकता है कि उपयोगकर्ता के पास सही अनुमतियाँ हैं।

समस्या यह है कि CanExecute को दिया गया पैरामीटर NULL है जिसे पहली बार कहा जाता है - इसलिए मैं कमांड को सक्षम / अक्षम करने के लिए तर्क नहीं चला सकता। हालाँकि, अगर मैं इसे सक्षम बनाता हूं, और फिर कमांड को निष्पादित करने के लिए बटन पर क्लिक करें, कमांडपार्टीमीटर सही तरीके से पास किया गया है। तो इसका मतलब है कि CommandParameter के खिलाफ बाध्यकारी काम कर रहा है।

ItemControl और DataTemplate के लिए XAML इस तरह दिखता है:

<ItemsControl 
    x:Name="commentsList"
    ItemsSource="{Binding Path=SharedDataItemPM.Comments}"
    Width="Auto" Height="Auto">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Button                             
                    Content="Delete"
                    FontSize="10"
                    Command="{Binding Path=DataContext.DeleteCommentCommand, ElementName=commentsList}" 
                    CommandParameter="{Binding}" />
            </StackPanel>                       
         </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

तो जैसा कि आप देख सकते हैं कि मेरे पास टिप्पणियों की सूची है। मैं चाहता हूँ कि DeleteCommentCommand का CommandParameter कमांड ऑब्जेक्ट के लिए बाध्य हो।

इसलिए मुझे लगता है कि मेरा सवाल है: क्या किसी ने पहले इस समस्या का अनुभव किया है? CanExecute को मेरी कमांड पर बुलाया जाता है, लेकिन पैरामीटर हमेशा NULL होता है - ऐसा क्यों है?

अपडेट: मैं समस्या को थोड़ा कम करने में सक्षम था। मैंने एक खाली डीबग ValueConverter जोड़ा ताकि मैं कमांडपैरमीटर डेटा बाउंड होने पर संदेश को आउटपुट कर सकूं। समस्या यह है कि CommandParameter बटन पर बँधने से पहले CanExecute पद्धति निष्पादित हो जाती है। मैंने कमांडपार्टीमीटर को कमांड से पहले सेट करने की कोशिश की है (जैसा कि सुझाव दिया गया है) - लेकिन यह अभी भी काम नहीं करता है। इसे कैसे नियंत्रित किया जाए, इस पर कोई सुझाव।

अपडेट 2: क्या बंधन "किए जाने" का पता लगाने का कोई तरीका है, ताकि मैं कमांड के पुनर्मूल्यांकन को मजबूर कर सकूं? इसके अलावा - क्या यह एक समस्या है कि मेरे पास कई बटन हैं (प्रत्येक आइटम के लिए आइटमकंट्रोल में) जो कमांड-ऑब्जेक्ट के एक ही उदाहरण के लिए बाध्य हैं?

अपडेट 3: मैंने अपने स्काईड्राइव को बग का प्रजनन अपलोड किया है: http://cid-1a08c11c407c0d8e.skydrive.live.com/self.aspx/Code%20samples/CommandParameterBinding.zip


मैं एक ही समस्या है, एक सूची बॉक्स के साथ।
हादी एस्कंदरी

इस मुद्दे के लिए WPF के खिलाफ वर्तमान में एक खुली बग रिपोर्ट है: github.com/dotnet/wpf/issues/316
UuDdLrLrSs

जवाबों:


14

मैं इसी तरह की समस्या पर लड़खड़ाया और अपने भरोसेमंद ट्राइगरकोर्टर का उपयोग कर इसे हल किया।

public class TriggerConverter : IMultiValueConverter
{
    #region IMultiValueConverter Members

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // First value is target value.
        // All others are update triggers only.
        if (values.Length < 1) return Binding.DoNothing;
        return values[0];
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

यह मान कनवर्टर किसी भी संख्या में पैरामीटर लेता है और उनमें से पहले को परिवर्तित मान के रूप में वापस करता है। जब आपके मामले में एक मल्टीबाइंडिंग में उपयोग किया जाता है तो यह निम्नलिखित जैसा दिखता है।

<ItemsControl 
    x:Name="commentsList"
    ItemsSource="{Binding Path=SharedDataItemPM.Comments}"
    Width="Auto" Height="Auto">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <Button                             
                    Content="Delete"
                    FontSize="10"
                    CommandParameter="{Binding}">
                    <Button.Command>
                        <MultiBinding Converter="{StaticResource TriggerConverter}">
                            <Binding Path="DataContext.DeleteCommentCommand"
                                     ElementName="commentsList" />
                            <Binding />
                        </MultiBinding> 
                    </Button.Command>
                </Button>
            </StackPanel>                                       
         </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

इस कार्य के लिए आपको कहीं न कहीं एक संसाधन के रूप में TriggerConverter को जोड़ना होगा। अब कमांड प्रॉपर्टी सेट हो गई है न कि कमांडपैरमीटर के लिए मान उपलब्ध हो गया है। आप इसके बजाय RelativeSource.Self और CommandParameter से भी जुड़ सकते हैं। उसी प्रभाव को प्राप्त करने के लिए।


2
इसने मेरे लिए काम किया। मुझे समझ नहीं आता क्यों। क्या कोई समझा सकता है?
TJKjaer

क्या यह काम नहीं करता है क्योंकि कमांडपार्टीमीटर कमांड से पहले बाध्य है? मुझे संदेह है कि आपको कनवर्टर की आवश्यकता होगी ...
MBoros

2
यह कोई हल नहीं है। यह हैक है? क्या तमाशा चल रहा है? यह काम करता था?
जॉर्डन

बिल्कुल सही, मेरे लिए काम करता है! मैजिक <बाइंडिंग /> लाइन में है, जो डेटा टेम्प्लेट में बदलाव होने पर कमांड बाइंडिंग को अपडेट करने का कारण बनता है (जो कि कमांड पैरामीटर के लिए बाध्य है)
एंड्रियास काहलर

56

मैं अपने दृश्य मॉडल पर एक कमांड को बांधने की कोशिश करते समय यह एक ही मुद्दा था।

मैंने इसे नाम से तत्व को संदर्भित करने के बजाय एक रिश्तेदार स्रोत बंधन का उपयोग करने के लिए बदल दिया और इसने चाल चली। पैरामीटर बाइंडिंग परिवर्तित नहीं हुई।

पुराना कोड:

Command="{Binding DataContext.MyCommand, ElementName=myWindow}"

नया कोड:

Command="{Binding DataContext.MyCommand, RelativeSource={RelativeSource AncestorType=Views:MyView}}"

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

CommandParameter="{Binding Groups}"
Command="{Binding StartCommand}"

42
CommandParameter को Command के सामने ले जाना इस थ्रेड पर सबसे अच्छा उत्तर है।
BSick7

6
विशेषताओं के क्रम को आगे बढ़ाने से हमें मदद नहीं मिली। मुझे आश्चर्य होगा कि अगर निष्पादन के आदेश पर इसका प्रभाव होता।
जैक उलेजा

3
मुझे नहीं पता कि यह क्यों काम करता है। ऐसा लगता है कि ऐसा नहीं होना चाहिए लेकिन यह पूरी तरह से करता है।
आरएमके

1
मेरे पास एक ही समस्या थी - RelativeSource ने मदद नहीं की, विशेषताओं के क्रम को बदलना। अद्यतन के लिए धन्यवाद!
ग्रांट क्रॉफ्टन

14
एक व्यक्ति के रूप में जो धार्मिक रूप से एक्सएएमएल को स्वचालित रूप से सुशोभित करने के लिए एक्सटेंशन का उपयोग करता है (लाइनों में विभाजित विशेषताओं को ठीक करता है, इंडेंटेशन को फिर से सेट करता है) के क्रम को बदलने CommandParameterऔर Commandमुझे डराता है।
गुत्से

29

मैंने पाया है कि मैंने जिस आदेश में Command और CommandParameter सेट किया है, उससे फर्क पड़ता है। कमांड प्रॉपर्टी सेट करने से CanExecute को तुरंत कॉल किया जा सकता है, इसलिए आप चाहते हैं कि CommandParameter पहले से ही उस बिंदु पर सेट हो।

मैंने पाया है कि XAML में गुणों के क्रम को बदलने से वास्तव में प्रभाव पड़ सकता है, हालांकि मुझे विश्वास नहीं है कि यह आपकी समस्या को हल करेगा। इस योग्य यद्यपि एक प्रयास।

आपको यह सुझाव दिया जा रहा है कि बटन कभी भी सक्षम नहीं होगा, जो आश्चर्य की बात है, क्योंकि मैं उम्मीद करूंगा कि कमांडपार्टर आपके उदाहरण में कमांड प्रॉपर्टी के तुरंत बाद सेट किया जाएगा। क्या CommandManager.InvalidateRequerySuggested () कॉलिंग बटन सक्षम होने का कारण बनता है?


3
कमांड से पहले कमांडपैरमीटर सेट करने की कोशिश की - अभी भी CanExecute निष्पादित करता है, लेकिन अभी भी NULL ... Bummer में गुजर रहा है - लेकिन टिप के लिए धन्यवाद। इसके अलावा, CommandManager.InvalidateRequerySuggested () को कॉल करना; कोई फर्क नहीं पड़ता।
जोनास फोल्लेसो

CommandManager.InvalidateRequerySuggested () ने मेरे लिए एक समान समस्या हल की। धन्यवाद!
एमजेएस

13

मैं इस मुद्दे के आसपास काम करने के लिए एक और विकल्प के साथ आया हूं जिसे मैं साझा करना चाहता था। क्योंकि CommandParameter प्रॉपर्टी सेट होने से पहले कमांड का CanExecute मेथड निष्पादित हो जाता है, मैंने एक अटैच्ड प्रॉपर्टी के साथ एक हेल्पर क्लास बनाया जो बाध्यकारी बदलाव होने पर CanExecute मेथड को फिर से कॉल करने के लिए मजबूर करता है।

public static class ButtonHelper
{
    public static DependencyProperty CommandParameterProperty = DependencyProperty.RegisterAttached(
        "CommandParameter",
        typeof(object),
        typeof(ButtonHelper),
        new PropertyMetadata(CommandParameter_Changed));

    private static void CommandParameter_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = d as ButtonBase;
        if (target == null)
            return;

        target.CommandParameter = e.NewValue;
        var temp = target.Command;
        // Have to set it to null first or CanExecute won't be called.
        target.Command = null;
        target.Command = temp;
    }

    public static object GetCommandParameter(ButtonBase target)
    {
        return target.GetValue(CommandParameterProperty);
    }

    public static void SetCommandParameter(ButtonBase target, object value)
    {
        target.SetValue(CommandParameterProperty, value);
    }
}

और फिर बटन पर आप एक कमांड पैरामीटर को बांधना चाहते हैं ...

<Button 
    Content="Press Me"
    Command="{Binding}" 
    helpers:ButtonHelper.CommandParameter="{Binding MyParameter}" />

मुझे उम्मीद है कि यह शायद किसी और मुद्दे के साथ मदद करता है।


अच्छी तरह से किया, धन्यवाद। मुझे विश्वास नहीं हो रहा है कि M $ ने 8 साल बाद इसे ठीक नहीं किया है। Turrible!
McGarnagle

8

यह एक पुराना धागा है, लेकिन जब से Google ने मुझे यहां लाया था जब मेरे पास यह मुद्दा था, मैं एक बटन के साथ DataGridTemplateColumn के लिए मेरे लिए जो काम करता हूं उसे जोड़ूंगा।

बाइंडिंग को इससे बदलें:

CommandParameter="{Binding .}"

सेवा

CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Self}}"

निश्चित नहीं है कि यह क्यों काम करता है, लेकिन इसने मेरे लिए किया।


मैंने ऊपर दिए गए दोनों उच्च स्कोर उत्तरों की कोशिश की है, लेकिन यह केवल मेरे लिए काम करता है। ऐसा लगता है कि यह नियंत्रण की आंतरिक समस्या है न कि बाध्यकारी।, लेकिन फिर भी कई लोगों ने इसे उपरोक्त उत्तरों के साथ काम किया। धन्यवाद!
javidan

6

मैं हाल ही में एक ही समस्या के लिए आया था (मेरे लिए यह एक संदर्भ मेनू में मेनू आइटम के लिए था), nad जबकि यह हर स्थिति के लिए एक उपयुक्त समाधान नहीं हो सकता है, मैंने इसे हल करने का एक अलग (और बहुत छोटा!) तरीका पाया। मुसीबत:

<MenuItem Header="Open file" Command="{Binding Tag.CommandOpenFile, IsAsync=True, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" CommandParameter="{Binding Name}" />

Tagसंदर्भ मेनू के विशेष मामले के लिए -बेड वर्कअराउंड को अनदेखा करना , यहां कुंजी CommandParameterनियमित रूप से बांधने के लिए है , लेकिन Commandअतिरिक्त के साथ बांधें IsAsync=True। यह वास्तविक कमांड (और इसलिए इसकी CanExecuteकॉल) के बंधन में थोड़ी देरी करेगा , इसलिए पैरामीटर पहले से ही उपलब्ध होगा। हालांकि, इसका मतलब है कि एक संक्षिप्त क्षण के लिए, सक्षम-राज्य गलत हो सकता है, लेकिन मेरे मामले के लिए, यह पूरी तरह से स्वीकार्य था।


5

हो सकता है CommandParameterBehaviorकि आप मेरी उपयोग करने में सक्षम हों जिन्हें मैंने कल प्रिज्म मंचों पर पोस्ट किया था । यह लापता व्यवहार को जोड़ता है जहां CommandParameterकारण के परिवर्तन को Commandफिर से उद्धृत किया जाता है।

यदि आप PropertyDescriptor.AddValueChangedबाद में कॉल किए बिना कॉल करते हैं, तो स्मृति रिसाव से बचने के मेरे प्रयासों के कारण यहां कुछ जटिलता है PropertyDescriptor.RemoveValueChanged। मैं कोशिश करता हूं और ठीक करता हूं कि जब हैंडीकैम अनलोड हो जाए तो हैंडलर को अनरजिस्टर्ड करके।

IDelegateCommandजब तक आप प्रिज्म का उपयोग नहीं कर रहे हैं (और प्रिज्म लाइब्रेरी में मेरे जैसे ही बदलाव करना चाहते हैं) आपको सामान निकालने की आवश्यकता होगी । यह भी ध्यान दें कि हम आम तौर पर RoutedCommandयहाँ का उपयोग नहीं करते हैं (हम प्रिज्म का उपयोग DelegateCommand<T>बहुत अधिक हर चीज के लिए करते हैं) इसलिए कृपया मुझे ज़िम्मेदार न CommandManager.InvalidateRequerySuggestedठहराएं अगर मेरा फोन किसी तरह के क्वांटम वेवफंटियन पतन कैस्केड को सेट करता है जो ज्ञात ब्रह्मांड या कुछ भी नष्ट कर देता है।

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Input;

namespace Microsoft.Practices.Composite.Wpf.Commands
{
    /// <summary>
    /// This class provides an attached property that, when set to true, will cause changes to the element's CommandParameter to 
    /// trigger the CanExecute handler to be called on the Command.
    /// </summary>
    public static class CommandParameterBehavior
    {
        /// <summary>
        /// Identifies the IsCommandRequeriedOnChange attached property
        /// </summary>
        /// <remarks>
        /// When a control has the <see cref="IsCommandRequeriedOnChangeProperty" />
        /// attached property set to true, then any change to it's 
        /// <see cref="System.Windows.Controls.Primitives.ButtonBase.CommandParameter" /> property will cause the state of
        /// the command attached to it's <see cref="System.Windows.Controls.Primitives.ButtonBase.Command" /> property to 
        /// be reevaluated.
        /// </remarks>
        public static readonly DependencyProperty IsCommandRequeriedOnChangeProperty =
            DependencyProperty.RegisterAttached("IsCommandRequeriedOnChange",
                                                typeof(bool),
                                                typeof(CommandParameterBehavior),
                                                new UIPropertyMetadata(false, new PropertyChangedCallback(OnIsCommandRequeriedOnChangeChanged)));

        /// <summary>
        /// Gets the value for the <see cref="IsCommandRequeriedOnChangeProperty"/> attached property.
        /// </summary>
        /// <param name="target">The object to adapt.</param>
        /// <returns>Whether the update on change behavior is enabled.</returns>
        public static bool GetIsCommandRequeriedOnChange(DependencyObject target)
        {
            return (bool)target.GetValue(IsCommandRequeriedOnChangeProperty);
        }

        /// <summary>
        /// Sets the <see cref="IsCommandRequeriedOnChangeProperty"/> attached property.
        /// </summary>
        /// <param name="target">The object to adapt. This is typically a <see cref="System.Windows.Controls.Primitives.ButtonBase" />, 
        /// <see cref="System.Windows.Controls.MenuItem" /> or <see cref="System.Windows.Documents.Hyperlink" /></param>
        /// <param name="value">Whether the update behaviour should be enabled.</param>
        public static void SetIsCommandRequeriedOnChange(DependencyObject target, bool value)
        {
            target.SetValue(IsCommandRequeriedOnChangeProperty, value);
        }

        private static void OnIsCommandRequeriedOnChangeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (!(d is ICommandSource))
                return;

            if (!(d is FrameworkElement || d is FrameworkContentElement))
                return;

            if ((bool)e.NewValue)
            {
                HookCommandParameterChanged(d);
            }
            else
            {
                UnhookCommandParameterChanged(d);
            }

            UpdateCommandState(d);
        }

        private static PropertyDescriptor GetCommandParameterPropertyDescriptor(object source)
        {
            return TypeDescriptor.GetProperties(source.GetType())["CommandParameter"];
        }

        private static void HookCommandParameterChanged(object source)
        {
            var propertyDescriptor = GetCommandParameterPropertyDescriptor(source);
            propertyDescriptor.AddValueChanged(source, OnCommandParameterChanged);

            // N.B. Using PropertyDescriptor.AddValueChanged will cause "source" to never be garbage collected,
            // so we need to hook the Unloaded event and call RemoveValueChanged there.
            HookUnloaded(source);
        }

        private static void UnhookCommandParameterChanged(object source)
        {
            var propertyDescriptor = GetCommandParameterPropertyDescriptor(source);
            propertyDescriptor.RemoveValueChanged(source, OnCommandParameterChanged);

            UnhookUnloaded(source);
        }

        private static void HookUnloaded(object source)
        {
            var fe = source as FrameworkElement;
            if (fe != null)
            {
                fe.Unloaded += OnUnloaded;
            }

            var fce = source as FrameworkContentElement;
            if (fce != null)
            {
                fce.Unloaded += OnUnloaded;
            }
        }

        private static void UnhookUnloaded(object source)
        {
            var fe = source as FrameworkElement;
            if (fe != null)
            {
                fe.Unloaded -= OnUnloaded;
            }

            var fce = source as FrameworkContentElement;
            if (fce != null)
            {
                fce.Unloaded -= OnUnloaded;
            }
        }

        static void OnUnloaded(object sender, RoutedEventArgs e)
        {
            UnhookCommandParameterChanged(sender);
        }

        static void OnCommandParameterChanged(object sender, EventArgs ea)
        {
            UpdateCommandState(sender);
        }

        private static void UpdateCommandState(object target)
        {
            var commandSource = target as ICommandSource;

            if (commandSource == null)
                return;

            var rc = commandSource.Command as RoutedCommand;
            if (rc != null)
            {
                CommandManager.InvalidateRequerySuggested();
            }

            var dc = commandSource.Command as IDelegateCommand;
            if (dc != null)
            {
                dc.RaiseCanExecuteChanged();
            }

        }
    }
}

कनेक्ट पर आपकी बग रिपोर्ट आई। कोई भी मौका जिससे आप अपनी पोस्ट को अपने अंतिम कोड के साथ यहां अपडेट कर सकें? या जब से तुम एक बेहतर काम मिल गया है?
मार्कस हुटर

एक आसान समाधान हो सकता है कि कमांड प्रॉपर सम्‍पत्ति का निरीक्षण करने के लिए प्रॉपर्टी डिस्क्रिप्‍टर के बजाए बाइंडिंग का उपयोग किया जाए। अन्यथा एक महान समाधान! यह वास्तव में केवल एक अजीब हैक या वर्कअराउंड शुरू करने के बजाय अंतर्निहित मुद्दे को ठीक करता है।
सेबेस्टियन नेग्रास्ज़स

1

DelegateCommand के साथ इस समस्या को "ठीक" करने का एक अपेक्षाकृत सरल तरीका है, हालांकि इसके लिए DelegateCommand स्रोत को अपडेट करने और Microsoft.Practices.Composite.Presentation.dll को फिर से संकलित करने की आवश्यकता है।

1) प्रिज्म 1.2 स्रोत कोड डाउनलोड करें और कम्पोजिटऐप्लीकेशनलाइड्स_Desktop.sln खोलें। यहाँ पर एक कंपोजिट है।प्रेसेशन.डेस्कटॉप प्रोजेक्ट है जिसमें डेलीगेटकोमांड स्रोत है।

2) सार्वजनिक कार्यक्रम EventHandler CanExecuteChanged के तहत, निम्नानुसार पढ़ने के लिए संशोधित करें:

public event EventHandler CanExecuteChanged
{
     add
     {
          WeakEventHandlerManager.AddWeakReferenceHandler( ref _canExecuteChangedHandlers, value, 2 );
          // add this line
          CommandManager.RequerySuggested += value;
     }
     remove
     {
          WeakEventHandlerManager.RemoveWeakReferenceHandler( _canExecuteChangedHandlers, value );
          // add this line
          CommandManager.RequerySuggested -= value;
     }
}

3) संरक्षित आभासी शून्य OnCanExecuteChanged () के तहत, इसे निम्नानुसार संशोधित करें:

protected virtual void OnCanExecuteChanged()
{
     // add this line
     CommandManager.InvalidateRequerySuggested();
     WeakEventHandlerManager.CallWeakReferenceHandlers( this, _canExecuteChangedHandlers );
}

4) समाधान को पुनःप्राप्त करें, फिर डीबग या रिलीज़ फ़ोल्डर में नेविगेट करें जहां संकलित DLL रहते हैं। Microsoft.Practices.Composite.Presentation.dll और .pdb (यदि आप चाहें तो) को कॉपी करें जहां आप अपने बाहरी असेंबली का संदर्भ देते हैं, और फिर नए संस्करणों को खींचने के लिए अपने आवेदन को फिर से जोड़ें।

इसके बाद, हर बार जब यूआई प्रश्न में डेलिगेटकमांड के लिए बाध्य तत्वों को प्रस्तुत करता है, तो CanExecute को निकाल दिया जाना चाहिए।

ध्यान रखना, जो

जीमेल पर रेफरी


1

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

public event EventHandler CanExecuteChanged;

मैंने इसे बदल दिया:

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

मैंने निम्नलिखित दो विधियों को हटा दिया क्योंकि मैं उन्हें ठीक करने के लिए बहुत आलसी था

public void RaiseCanExecuteChanged()

तथा

protected virtual void OnCanExecuteChanged()

और यह सब ... यह सुनिश्चित करने के लिए लगता है कि बाइंडिंग बदलने के बाद और Execute विधि के बाद CanExecute कहा जाएगा

अगर ViewModel को बदल दिया जाए तो यह स्वचालित रूप से ट्रिगर नहीं होगा, लेकिन जैसा कि इस धागे में CommandManager को कॉल करके संभव है। InvalidateRequery GUI थ्रेड पर उपलब्ध

Application.Current?.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)CommandManager.InvalidateRequerySuggested);

मैंने पाया है कि DispatcherPriority.Normalमज़बूती से काम करने के लिए बहुत अधिक है (या मेरे मामले में)। का उपयोग करते हुए DispatcherPriority.Loadedकाम करता है अच्छी तरह से, और अधिक उपयुक्त लग रहा है (यानी स्पष्ट संकेत है कि प्रतिनिधि लागू किया जा करने के लिए जब तक दृश्य मॉडल के साथ जुड़ी UI तत्व वास्तव में लोड किया गया है नहीं है)।
पीटर डुनिहो

0

हे जोनास, यकीन नहीं है कि यह डेटा टेम्प्लेट में काम करेगा, लेकिन यहाँ एक कमांड पैरामीटर के रूप में वर्तमान आइटम को हथियाने के लिए एक सूची दृश्य संदर्भ मेनू में उपयोग किया जाने वाला बाइंडिंग सिंटैक्स है:

CommandParameter = "{RelativeSource = {RelativeSource AncestorType = ContextMenu}, Path = PlacementTarget.SelectedItem, Mode = TwoWay}"


मैं अपनी सूची के दृश्य में ठीक वही काम करता हूं। इस मामले में यह एक ItemControl है, इसलिए (दृश्य पेड़ में) के खिलाफ "बाइंड अप" करने के लिए कोई स्पष्ट संपत्ति नहीं है। मुझे लगता है कि मुझे बाध्यकारी होने पर पता लगाने का एक तरीका खोजना होगा, और CanExecute का पुनर्मूल्यांकन करना होगा (क्योंकि CommandParameter बाध्य हो जाता है, बस देर से)
Jonas Follesø


0

इनमें से कुछ उत्तर कमांड को प्राप्त करने के लिए DataContext के लिए बाध्य करने के बारे में हैं, लेकिन यह प्रश्न कमांडपैरमीटर के बारे में था कि जब यह नहीं होना चाहिए, तो यह शून्य था। हमने भी इसका अनुभव किया। एक कूबड़ पर, हमें अपने ViewModel में काम करने के लिए एक बहुत ही सरल तरीका मिला। यह विशेष रूप से CommandParameter null समस्या के लिए ग्राहक द्वारा रिपोर्ट की गई, कोड की एक पंक्ति के साथ है। Dispatcher.BeginInvoke () नोट करें।

public DelegateCommand<objectToBePassed> CommandShowReport
    {
        get
        {
            // create the command, or pass what is already created.
            var command = _commandShowReport ?? (_commandShowReport = new DelegateCommand<object>(OnCommandShowReport, OnCanCommandShowReport));

            // For the item template, the OnCanCommand will first pass in null. This will tell the command to re-pass the command param to validate if it can execute.
            Dispatcher.BeginInvoke((Action) delegate { command.RaiseCanExecuteChanged(); }, DispatcherPriority.DataBind);

            return command;
        }
    }

-1

इसका लंबा शॉट है। यह डिबग करने के लिए आप कोशिश कर सकते हैं:
- PreviewCanExecute ईवेंट की जाँच करना।
- अंदर झांकने के लिए स्नूप / wpf तिल का उपयोग करें और देखें कि कमांडरमीटर क्या है।

HTH,


स्नूप का उपयोग करने की कोशिश की - लेकिन यह वास्तव में डिबग करना कठिन है क्योंकि यह केवल तभी शुरू होता है जब यह शुरू में लोड होता है। अगर मैं इस पर स्नूप चलाता हूं, तो कमांड और कमांडपार्टर दोनों सेठ हैं ... इसका डेटाटमप्लेट में कमांड का उपयोग करने के साथ करना है।
जोनास फोलेस्को

-1

CommandManager.InvalidateRequerySuggested मेरे लिए भी काम करता है। मेरा मानना ​​है कि निम्न लिंक समान समस्या के बारे में बात करती है, और एम $ देव ने वर्तमान संस्करण में सीमा की पुष्टि की है, और कमांड मैनजर ।InvalidateRequerySuggested काम है। http://social.expression.microsoft.com/Forums/en-US/wpf/thread/c45d2272-e8ba-4219-bb41-1e5eaed08a1f/

कमांडमैन को आमंत्रित करने का समय कितना महत्वपूर्ण है। InvalidateRequerySuggested। प्रासंगिक मूल्य परिवर्तन अधिसूचित होने के बाद इसे लागू किया जाना चाहिए।


वह लिंक अब मान्य नहीं है
पीटर डनिहो

-2

CommandParameter को Command से पहले सेट करने पर Ed Ball के सुझाव के अलावा , सुनिश्चित करें कि आपके CanExecute मेथड में ऑब्जेक्ट का पैरामीटर हो प्रकार ।

private bool OnDeleteSelectedItemsCanExecute(object SelectedItems)  
{
    // Your goes heres
}

आशा है कि यह किसी को उस समय की भारी मात्रा में खर्च करने से रोकता है जो मैंने चुना था कि कैसे यह चुना जा सकता है

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