WPF CommandParameter jest NULL przy pierwszym wywołaniu CanExecute

Napotkałem problem z WPF i poleceń, które są związane z przyciskiem wewnątrz płyty danych ItemsControl. Scenariusz jest dość prosty. Kontrolka ItemsControl jest powiązana z listą obiektów i chcę móc usunąć każdy obiekt z listy, klikając przycisk. Przycisk wykonuje polecenie, a polecenie zajmuje się usuwaniem. Parametr CommandParameter jest powiązany z obiektem, który chcę usunąć. W ten sposób wiem, co użytkownik kliknął. Użytkownik powinien tylko być w stanie usunąć swoje "własne" obiekty - więc muszę wykonać kilka sprawdzeń w wywołaniu "CanExecute" polecenia, aby sprawdzić, czy użytkownik ma odpowiednie uprawnienia.

Problem polega na tym, że parametr przekazany do CanExecute jest NULL przy pierwszym wywołaniu - więc nie mogę uruchomić logiki, aby włączyć / wyłączyć polecenie. Jeśli jednak włączę go zawsze, a następnie kliknę przycisk, aby wykonać polecenie, parametr CommandParameter zostanie przekazany poprawnie. Oznacza to, że wiążąca wobec parametr dowodzenia działa.

XAML dla ItemsControl i DataTemplate wygląda tak:

<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>

Więc jak widać mam listę obiektów komentarzy. Chcę, aby parametr CommandParameter polecenia DeleteCommentCommand był powiązany z obiektem Command.

Więc moje pytanie brzmi: czy ktoś wcześniej doświadczył tego problemu? CanExecute jest wywoływany na moje polecenie, ale parametr jest zawsze NULL za pierwszym razem-dlaczego tak jest?

Update: byłem może trochę zawęzić problem. Dodałem pusty Debug ValueConverter tak, że mogłem wypisać wiadomość, gdy parametr CommandParameter jest związany z danymi. Okazuje się, że problem polega na tym, że metoda CanExecute jest wykonywana przed powiązaniem parametru CommandParameter z przyciskiem. Próbowałem ustawić CommandParameter przed poleceniem (jak sugerowano) - ale nadal nie działa. Jakieś wskazówki, jak to kontrolować.

Update2: Czy Jest jakiś sposób, aby wykryć, kiedy powiązanie jest "zrobione", więc że mogę wymusić ponowną ocenę dowództwa? Również - czy jest to problem, że mam wiele przycisków (po jednym dla każdej pozycji w ItemsControl), które wiążą się z tą samą instancją obiektu polecenia?

Update3: wgrałem reprodukcję błędu do mojego SkyDrive: http://cid-1a08c11c407c0d8e.skydrive.live.com/self.aspx/Code%20samples/CommandParameterBinding.zip

Author: Jonas Follesø, 2008-12-02

15 answers

Natknąłem się na podobny problem i rozwiązałem go za pomocą mojego wiernego Triggerconvertera.

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
}

Ten konwerter wartości pobiera dowolną liczbę parametrów i przekazuje pierwszy z nich z powrotem jako przekonwertowaną wartość. Gdy jest używany w MultiBinding w Twoim przypadku wygląda to następująco.

<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>

Będziesz musiał dodać gdzieś TriggerConverter jako zasób, aby to działało. Teraz właściwość Command jest ustawiana dopiero przed udostępnieniem wartości parametru CommandParameter. Mógłbyś nawet powiązać z RelativeSource.Self i CommandParameter zamiast . aby osiągnąć ten sam efekt.

 14
Author: David Liersch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-05 16:22:50

Miałem ten sam problem podczas próby powiązania z poleceniem w moim modelu widoku.

Zmieniłem go, aby użyć względnego powiązania źródła, a nie odwoływać się do elementu po nazwie i to załatwiło sprawę. Powiązanie parametrów nie uległo zmianie.

Stary Kod:

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

Nowy Kod:

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

Update: właśnie natknąłem się na ten problem bez użycia ElementName, wiążę się z poleceniem w moim modelu widoku, a moim kontekstem danych przycisku jest mój model widoku. W tym przypadku Musiałem po prostu przesunąć atrybut CommandParameter przed atrybutem Command w deklaracji przycisku (w XAML).

CommandParameter="{Binding Groups}"
Command="{Binding StartCommand}"
 57
Author: Travis Weber,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-11-17 16:43:34

Odkryłem, że kolejność w jakiej ustawiam Command i CommandParameter robi różnicę. Ustawienie właściwości Command powoduje, że CanExecute zostanie wywołane natychmiast, więc chcesz, aby CommandParameter był już ustawiony w tym punkcie.

Odkryłem, że zmiana kolejności właściwości w XAML może rzeczywiście mieć wpływ, choć nie jestem pewien, czy rozwiąże to twój problem. Warto spróbować.

Sugerujesz, że przycisk nigdy nie staje się włączone, co jest zaskakujące, ponieważ spodziewałbym się, że CommandParameter zostanie ustawiony krótko po właściwości Command w twoim przykładzie. Wywołuje CommandManager.InvalidateRequerySuggested () powoduje włączenie przycisku?

 30
Author: Ed Ball,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-03 04:59:55

Wymyśliłem inną opcję obejścia tego problemu, którym chciałem się podzielić. Ponieważ metoda CanExecute polecenia zostanie wykonana przed ustawieniem właściwości CommandParameter, utworzyłem klasę pomocniczą z dołączoną właściwością, która wymusza ponowne wywołanie metody CanExecute przy zmianie powiązania.

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);
    }
}

A następnie na przycisku, do którego chcesz powiązać parametr polecenia...

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

Mam nadzieję, że to może pomóc komuś innemu w tym problemie.

 13
Author: Ed Downs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-05-15 15:54:36

To jest stary wątek, ale ponieważ Google przyniósł mi tutaj, gdy miałem ten problem, dodam to, co działało dla mnie dla DataGridTemplateColumn z przyciskiem.

Zmień wiązanie z:

CommandParameter="{Binding .}"

Do

CommandParameter="{Binding DataContext, RelativeSource={RelativeSource Self}}"
Nie wiem, dlaczego to działa, ale dla mnie tak.
 8
Author: Simon Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-08-15 18:46:40

Ostatnio natknąłem się na ten sam problem (dla mnie było to dla pozycji menu w menu kontekstowym), nad chociaż może nie być odpowiednim rozwiązaniem dla każdej sytuacji, znalazłem inny (i dużo krótszy!) sposób rozwiązania tego problemu:

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

Ignorując obejście oparte na Tag dla specjalnego przypadku menu kontekstowego, kluczem jest regularne powiązanie CommandParameter, ale powiązanie Command z dodatkowym IsAsync=True. To opóźni powiązanie rzeczywistego polecenia (a więc jego CanExecute wywołanie) trochę, więc parametr będzie już dostępny. Oznacza to jednak, że przez krótką chwilę stan włączony może się mylić, ale w moim przypadku było to całkowicie dopuszczalne.

 6
Author: Ralf Stauder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-10 12:37:26

Być może będziecie mogli skorzystać z mojego CommandParameterBehavior, który zamieściłem wczoraj na forach Prism. Dodaje brakujące zachowanie, w którym zmiana CommandParameter powoduje ponowne zapytanie Command.

Jest tu pewna złożoność spowodowana moimi próbami uniknięcia wycieku pamięci spowodowanego wywołaniem PropertyDescriptor.AddValueChanged bez późniejszego wywołania PropertyDescriptor.RemoveValueChanged. Staram się to naprawić poprzez wyrejestrowanie obsługi, gdy ekement jest rozładowany.

Prawdopodobnie będziesz musiał usunąć IDelegateCommand rzeczy, chyba że używasz Prism (i chcę wprowadzić te same zmiany co ja w Bibliotece Prism). Zauważ również, że na ogół nie używamy RoutedCommand s (używamy DelegateCommand<T> Prism do prawie wszystkiego), więc proszę, nie obwiniaj mnie za to, jeśli moje wezwanie do CommandManager.InvalidateRequerySuggested wywoła jakiś rodzaj kwantowej kaskady załamania fal, która niszczy znany wszechświat lub cokolwiek innego.

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();
            }

        }
    }
}
 5
Author: Swythan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-02-18 15:34:52

Istnieje stosunkowo prosty sposób na "naprawienie" tego problemu z DelegateCommand, chociaż wymaga to aktualizacji źródła DelegateCommand i ponownej kompilacji Microsoft.Praktyki./ Align = "left" / Prezentacja.dll.

1) Pobierz kod źródłowy Prism 1.2 i otwórz CompositeApplicationLibrary_Desktop.sln. Tutaj jest kompozycja.Prezentacja.Projekt pulpitu, który zawiera źródło DelegateCommand.

2) Pod publicznym wydarzeniem EventHandler CanExecuteChanged, modify to read as "follows": {]}

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) pod protected virtual void oncanexecutechanged () zmodyfikuj go w następujący sposób:

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

4) przekompiluj rozwiązanie, a następnie przejdź do folderu debugowania lub wydania, w którym żyją skompilowane biblioteki DLL. Skopiuj Microsoft.Praktyki./ Align = "left" / Prezentacja.dll i .pdb (jeśli chcesz) do miejsca, w którym odwołujesz się do zewnętrznych zestawów, a następnie przekompiluj aplikację, aby pobrać nowe wersje.

Po tym, CanExecute powinien być uruchamiany za każdym razem, gdy interfejs renderuje elementy związane z danym poleceniem Delegat.

Dbaj o siebie, Joe

Sędziuj w Gmailu

 1
Author: Joe Bako,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-08 18:09:11

Po przeczytaniu kilku dobrych odpowiedzi na podobne pytania zmieniłem w twoim przykładzie nieco DelegateCommand, aby to działało. Zamiast używać:

public event EventHandler CanExecuteChanged;

Zmieniłem na:

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

Usunąłem następujące dwie metody, ponieważ byłem zbyt leniwy, aby je naprawić

public void RaiseCanExecuteChanged()

I

protected virtual void OnCanExecuteChanged()
I to wszystko... wydaje się, że zapewnia to, że CanExecute zostanie wywołane po zmianie wiązania i po metodzie Execute

Nie uruchomi się automatycznie, jeśli ViewModel jest zmieniony, ale jak wspomniano w tym wątku możliwe przez wywołanie menedżera poleceń.Invalidaterequerysugged on the GUI thread

Application.Current?.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)CommandManager.InvalidateRequerySuggested);
 1
Author: kkCosmo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-29 10:41:34

Hej Jonas, Nie wiem, czy to będzie działać w szablonie danych, ale oto składnia wiążąca, której używam w menu kontekstowym ListView, aby pobrać bieżącą pozycję jako parametr polecenia:

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

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-04 14:26:06

Zarejestrowałem to jako błąd przeciwko WPF w. Net 4.0, ponieważ problem nadal istnieje w wersji Beta 2.

Https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=504976

 0
Author: Swythan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-11-26 14:18:40

Niektóre z tych odpowiedzi dotyczą powiązania z DataContext w celu uzyskania samego polecenia, ale pytanie dotyczyło tego, że parametr CommandParameter jest null, gdy nie powinien być. My też tego doświadczyliśmy. Na przeczucie, znaleźliśmy bardzo prosty sposób, aby to działa w naszym ViewModel. Jest to specjalnie dla problemu CommandParameter null zgłoszonego przez Klienta, z jedną linią kodu. Powiadom dyspozytora.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;
        }
    }
 0
Author: TravisWhidden,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-21 23:19:36

To strzał w dziesiątkę. aby to debugować możesz spróbować:
- sprawdzenie zdarzenia PreviewCanExecute.
- użyj snoop / WPF mole, aby zajrzeć do środka i zobaczyć, co to jest parametr commandparameter.

HTH,

 -1
Author: Dennis,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-04 04:55:53

Menedżer poleceń.InvalidateRequerySuggested działa również dla mnie. Uważam, że poniższy link mówi o podobnym problemie, a m$ dev potwierdził ograniczenie w bieżącej wersji, a commandManager.InvalidateRequerySuggested jest obejściem. http://social.expression.microsoft.com/Forums/en-US/wpf/thread/c45d2272-e8ba-4219-bb41-1e5eaed08a1f/

Ważny jest czas wywołania menedżera poleceń./ Align = "left" / Należy powołać się na to po powiadomieniu o odpowiedniej zmianie wartości.

 -1
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-22 05:57:30

Obok sugestii Ed Ball przy ustawieniu CommandParameter przed Command , upewnij się, że twoja metoda CanExecute ma parametr typu object .

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

Mam nadzieję, że uniemożliwi to komuś spędzanie ogromnej ilości czasu, którą zrobiłem, aby dowiedzieć się, jak odbierać SelectedItems jako parametr CanExecute

 -2
Author: Julio Nobre,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-02-07 11:40:16