WPF CommandParameter adalah NULL saat pertama kali CanExecute dipanggil

86

Saya mengalami masalah dengan WPF dan Perintah yang terikat ke Tombol di dalam DataTemplate dari ItemsControl. Skenarionya cukup lurus ke depan. ItemsControl terikat ke daftar objek, dan saya ingin dapat menghapus setiap objek dalam daftar dengan mengklik sebuah Tombol. Tombol menjalankan Perintah, dan Perintah menangani penghapusan. CommandParameter terikat ke Objek yang ingin saya hapus. Dengan cara itu saya tahu apa yang diklik pengguna. Seorang pengguna seharusnya hanya dapat menghapus objek "sendiri" mereka - jadi saya perlu melakukan beberapa pemeriksaan dalam panggilan "CanExecute" dari Perintah untuk memverifikasi bahwa pengguna memiliki izin yang tepat.

Masalahnya adalah bahwa parameter yang diteruskan ke CanExecute adalah NULL saat pertama kali dipanggil - jadi saya tidak dapat menjalankan logika untuk mengaktifkan / menonaktifkan perintah. Namun, jika saya membuatnya selalu diaktifkan, lalu mengklik tombol untuk menjalankan perintah, CommandParameter akan diteruskan dengan benar. Jadi itu berarti pengikatan terhadap CommandParameter berfungsi.

XAML untuk ItemsControl dan DataTemplate terlihat seperti ini:

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

Jadi seperti yang Anda lihat, saya memiliki daftar objek Komentar. Saya ingin CommandParameter dari DeleteCommentCommand terikat ke objek Command.

Jadi saya kira pertanyaan saya adalah: apakah ada yang pernah mengalami masalah ini sebelumnya? CanExecute dipanggil di Command saya, tetapi parameternya selalu NULL saat pertama kali - mengapa demikian?

Pembaruan: Saya dapat mempersempit masalah sedikit. Saya menambahkan Debug ValueConverter kosong sehingga saya bisa mengeluarkan pesan ketika CommandParameter terikat data. Ternyata masalahnya adalah metode CanExecute dijalankan sebelum CommandParameter terikat ke tombol. Saya telah mencoba mengatur CommandParameter sebelum Command (seperti yang disarankan) - tetapi masih tidak berhasil. Ada tips tentang cara mengontrolnya.

Pembaruan2: Apakah ada cara untuk mendeteksi kapan pengikatan "selesai", sehingga saya dapat memaksa evaluasi ulang perintah? Juga - apakah masalah saya memiliki beberapa Tombol (satu untuk setiap item di ItemsControl) yang terikat ke contoh yang sama dari objek-Perintah?

Pembaruan3: Saya telah mengunggah reproduksi bug ke SkyDrive saya: http://cid-1a08c11c407c0d8e.skydrive.live.com/self.aspx/Code%20samples/CommandParameterBinding.zip

Jonas Follesø
sumber
Saya memiliki masalah yang sama persis, dengan ListBox.
Hadi Eskandari
Saat ini ada laporan bug terhadap WPF yang terbuka untuk masalah ini: github.com/dotnet/wpf/issues/316
UuDdLrLrSs

Jawaban:

14

Saya menemukan masalah serupa dan menyelesaikannya menggunakan TriggerConverter saya yang terpercaya.

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
}

Pengonversi nilai ini mengambil sejumlah parameter dan meneruskan yang pertama kembali sebagai nilai yang dikonversi. Saat digunakan dalam MultiBinding dalam kasus Anda, tampilannya akan seperti berikut ini.

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

Anda harus menambahkan TriggerConverter sebagai sumber daya di suatu tempat agar ini berfungsi. Sekarang properti Command disetel sebelum nilai untuk CommandParameter tersedia. Anda bahkan dapat mengikat ke RelativeSource.Self dan CommandParameter, bukan. untuk mencapai efek yang sama.

David Liersch
sumber
2
Ini berhasil untuk saya. Saya tidak mengerti mengapa. Adakah yang bisa menjelaskan?
TJKjaer
Apakah tidak berhasil karena CommandParameter terikat sebelum Command? Saya ragu Anda akan membutuhkan konverter ...
MBoros
2
Ini bukanlah solusi. Ini hack? Apa yang sedang terjadi? Ini dulu bekerja?
Yordania
Sempurna, berhasil untuk saya! Keajaiban ada di baris <Binding />, yang menyebabkan pengikatan perintah diperbarui saat templat data berubah (yang terikat ke parameter perintah)
Andreas Kahler
57

Saya mengalami masalah yang sama saat mencoba mengikat perintah pada model tampilan saya.

Saya mengubahnya untuk menggunakan pengikatan sumber relatif daripada merujuk ke elemen dengan nama dan itu berhasil. Pengikatan parameter tidak berubah.

Kode Lama:

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

Kode Baru:

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

Pembaruan : Saya baru saja menemukan masalah ini tanpa menggunakan ElementName, saya mengikat perintah pada model tampilan saya dan konteks data tombol adalah model tampilan saya. Dalam hal ini saya hanya perlu memindahkan atribut CommandParameter sebelum atribut Command di deklarasi Tombol (di XAML).

CommandParameter="{Binding Groups}"
Command="{Binding StartCommand}"
Travis Weber
sumber
42
Memindahkan CommandParameter di depan Command adalah jawaban terbaik di utas ini.
BSick7
6
Memindahkan urutan atribut tidak membantu kami. Saya akan terkejut jika itu berpengaruh pada urutan eksekusi.
Jack Ukleja
3
Saya tidak tahu mengapa ini berhasil. Rasanya seperti tidak seharusnya tetapi benar-benar terjadi.
RMK
1
Saya memiliki masalah yang sama - RelativeSource tidak membantu, mengubah urutan atribut dapat membantu. Terima kasih atas pembaruannya!
Grant Crofton
14
Sebagai orang yang religius menggunakan ekstensi untuk secara otomatis mempercantik XAML (memisahkan atribut di garis, memperbaiki indentasi, menyusun ulang atribut), proposal untuk mengubah urutan CommandParameterdan Commandmembuatku takut.
Guttsy
29

Saya telah menemukan bahwa urutan saya mengatur Command dan CommandParameter membuat perbedaan. Menyetel properti Command menyebabkan CanExecute dipanggil segera, jadi Anda ingin CommandParameter sudah disetel pada saat itu.

Saya telah menemukan bahwa mengubah urutan properti di XAML sebenarnya dapat berpengaruh, meskipun saya tidak yakin hal itu akan menyelesaikan masalah Anda. Ini patut dicoba.

Anda sepertinya menyarankan bahwa tombol tidak pernah diaktifkan, yang mengejutkan, karena saya mengharapkan CommandParameter disetel segera setelah properti Command dalam contoh Anda. Apakah memanggil CommandManager.InvalidateRequerySuggested () menyebabkan tombol menjadi aktif?

Ed Ball
sumber
3
Mencoba mengatur CommandParameter sebelum Command - masih mengeksekusi CanExecute, tetapi masih meneruskan NULL ... Sial - tapi terima kasih atas tipnya. Juga, memanggil CommandManager.InvalidateRequerySuggested (); tidak ada bedanya.
Jonas Follesø
CommandManager.InvalidateRequerySuggested () memecahkan masalah serupa untuk saya. Terima kasih!
MJS
13

Saya telah menemukan opsi lain untuk mengatasi masalah ini yang ingin saya bagikan. Karena metode perintah CanExecute dieksekusi sebelum properti CommandParameter disetel, saya membuat kelas pembantu dengan properti terlampir yang memaksa metode CanExecute dipanggil lagi ketika pengikatan berubah.

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

Dan kemudian pada tombol Anda ingin mengikat parameter perintah ke ...

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

Saya harap ini dapat membantu orang lain dengan masalah ini.

Ed Downs
sumber
Selamat, terima kasih. Saya tidak percaya M $ belum memperbaiki ini setelah 8 tahun. Mengerikan!
McGarnagle
8

Ini adalah utas lama, tetapi karena Google membawa saya ke sini ketika saya mengalami masalah ini, saya akan menambahkan apa yang berhasil untuk saya untuk DataGridTemplateColumn dengan sebuah tombol.

Ubah pengikatan dari:

CommandParameter="{Binding .}"

untuk

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

Tidak yakin mengapa ini berhasil, tetapi berhasil untuk saya.

Simon Smith
sumber
Saya telah mencoba kedua jawaban skor tinggi di atas, tetapi yang ini hanya berhasil untuk saya. Tampaknya masalah internal kontrol itu sendiri bukan yang mengikat, tetapi masih banyak orang yang berhasil dengan jawaban di atas. Terima kasih!
Javidan
6

Saya baru-baru ini menemukan masalah yang sama (bagi saya itu untuk item menu dalam menu konteks), nad meskipun itu mungkin bukan solusi yang cocok untuk setiap situasi, saya menemukan cara yang berbeda (dan jauh lebih pendek!) Untuk menyelesaikannya masalah:

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

Mengabaikan Tagsolusi berbasis untuk kasus khusus menu konteks, kuncinya di sini adalah mengikat CommandParametersecara teratur, tetapi mengikat Commanddengan tambahan IsAsync=True. Ini akan sedikit menunda pengikatan perintah aktual (dan oleh karena itu CanExecutepanggilannya), sehingga parameter sudah tersedia. Ini berarti, meskipun, untuk sesaat, status-aktif mungkin salah, tetapi untuk kasus saya, itu bisa diterima.

Ralf Stauder
sumber
5

Anda mungkin dapat menggunakan milik saya CommandParameterBehavioryang saya posting ke forum Prism kemarin. Ini menambahkan perilaku yang hilang di mana perubahan CommandParameterpenyebab Commandharus dipertanyakan kembali.

Ada beberapa kerumitan di sini yang disebabkan oleh upaya saya untuk menghindari kebocoran memori yang disebabkan jika Anda menelepon PropertyDescriptor.AddValueChangedtanpa menelepon nanti PropertyDescriptor.RemoveValueChanged. Saya mencoba dan memperbaikinya dengan membatalkan registrasi pawang saat ekement dibongkar.

Anda mungkin perlu menghapus IDelegateCommandbarang - barang tersebut kecuali jika Anda menggunakan Prism (dan ingin membuat perubahan yang sama seperti saya pada perpustakaan Prism). Juga perhatikan bahwa kami umumnya tidak menggunakan RoutedCommands di sini (kami menggunakan Prism DelegateCommand<T>untuk hampir semua hal) jadi tolong jangan anggap saya bertanggung jawab jika panggilan saya untuk CommandManager.InvalidateRequerySuggestedmemicu semacam kaskade runtuhnya fungsi gelombang kuantum yang menghancurkan alam semesta yang diketahui atau apa pun.

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

        }
    }
}
Swythan
sumber
menemukan laporan bug Anda di connect. Adakah kemungkinan Anda dapat memperbarui posting Anda di sini dengan kode terakhir Anda ini? atau apakah Anda sudah menemukan pekerjaan yang lebih baik?
Markus Hütter
Solusi yang lebih mudah adalah dengan mengamati properti CommandParameter menggunakan pengikatan, bukan deskriptor properti. Jika tidak, solusi yang bagus! Yang ini benar-benar memperbaiki masalah yang mendasarinya alih-alih hanya memperkenalkan peretasan atau solusi yang canggung.
Sebastian Negraszus
1

Ada cara yang relatif sederhana untuk "memperbaiki" masalah ini dengan DelegateCommand, meskipun itu memerlukan pembaruan sumber DelegateCommand dan kompilasi ulang Microsoft.Practices.Composite.Presentation.dll.

1) Unduh kode sumber Prism 1.2 dan buka CompositeApplicationLibrary_Desktop.sln. Di sini adalah proyek Composite.Presentation.Desktop yang berisi sumber DelegateCommand.

2) Di bawah acara publik EventHandler CanExecuteChanged, ubah untuk membaca sebagai berikut:

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) Di bawah virtual void OnCanExecuteChanged () yang dilindungi, ubah sebagai berikut:

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

4) Kompilasi ulang solusi, lalu navigasikan ke folder Debug atau Rilis tempat DLL yang dikompilasi berada. Salin Microsoft.Practices.Composite.Presentation.dll dan .pdb (jika Anda ingin) ke tempat Anda mereferensikan rakitan eksternal Anda, dan kemudian kompilasi ulang aplikasi Anda untuk menarik versi baru.

Setelah ini, CanExecute harus diaktifkan setiap kali UI merender elemen yang terikat ke DelegateCommand yang dimaksud.

Jaga dirimu, Joe

refereejoe di gmail

Joe Bako
sumber
1

Setelah membaca beberapa jawaban bagus untuk pertanyaan serupa, saya mengubah sedikit Perintah Delegasi dalam contoh Anda untuk membuatnya berfungsi. Daripada menggunakan:

public event EventHandler CanExecuteChanged;

Saya mengubahnya menjadi:

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

Saya menghapus dua metode berikut karena saya terlalu malas untuk memperbaikinya

public void RaiseCanExecuteChanged()

dan

protected virtual void OnCanExecuteChanged()

Dan itu saja ... ini tampaknya memastikan bahwa CanExecute akan dipanggil saat Binding berubah dan setelah metode Execute

Ini tidak akan secara otomatis memicu jika ViewModel diubah tetapi seperti yang disebutkan di utas ini dimungkinkan dengan memanggil CommandManager.InvalidateRequerySuggested di utas GUI

Application.Current?.Dispatcher.Invoke(DispatcherPriority.Normal, (Action)CommandManager.InvalidateRequerySuggested);
kkCosmo.dll
sumber
Saya telah menemukan itu DispatcherPriority.Normalterlalu tinggi untuk bekerja dengan andal (atau sama sekali, dalam kasus saya). Penggunaan DispatcherPriority.Loadedberfungsi dengan baik, dan tampaknya lebih sesuai (yaitu secara eksplisit menunjukkan bahwa delegasi tidak akan dipanggil hingga elemen UI yang terkait dengan model tampilan sebenarnya telah dimuat).
Peter Duniho
0

Hai Jonas, tidak yakin apakah ini akan berfungsi di templat data, tetapi berikut adalah sintaks pengikatan yang saya gunakan dalam menu Konteks ListView untuk mengambil item saat ini sebagai parameter perintah:

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


sumber
Saya melakukan hal yang persis sama dalam tampilan daftar saya. Dalam hal ini adalah ItemsControl sehingga tidak ada properti yang jelas untuk "mengikat" (di pohon visual). Saya rasa saya harus menemukan cara untuk mendeteksi kapan pengikatan selesai, dan mengevaluasi ulang CanExecute (karena CommandParameter terikat, sampai terlambat)
Jonas Follesø
0

Beberapa dari jawaban ini adalah tentang mengikat ke DataContext untuk mendapatkan Perintah itu sendiri, tetapi pertanyaannya adalah tentang CommandParameter menjadi nol padahal seharusnya tidak. Kami juga mengalami ini. Berdasarkan firasat, kami menemukan cara yang sangat sederhana untuk membuatnya berfungsi di ViewModel kami. Ini khusus untuk masalah null CommandParameter yang dilaporkan oleh pelanggan, dengan satu baris kode. Perhatikan 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;
        }
    }
TravisWhidden
sumber
-1

Ini tembakan yang jauh. untuk men-debug ini, Anda dapat mencoba:
- memeriksa acara PreviewCanExecute.
- gunakan snoop / wpf mol untuk mengintip ke dalam dan melihat parameter perintahnya.

HTH,

Dennis
sumber
Mencoba menggunakan Snoop - tetapi sangat sulit untuk melakukan debug karena hanya NULL saat pertama kali dimuat. Jika saya menjalankan Snoop di atasnya, Command dan CommandParameter keduanya seth ... Ini ada hubungannya dengan menggunakan Perintah di DataTemplate.
Jonas Follesø
-1

CommandManager.InvalidateRequerySuggested juga berfungsi untuk saya. Saya yakin tautan berikut berbicara tentang masalah serupa, dan M $ dev mengkonfirmasi batasan dalam versi saat ini, dan commandManager.InvalidateRequerySuggested adalah solusinya.http://social.expression.microsoft.com/Forums/en-US/wpf/thread/c45d2272-e8ba-4219-bb41-1e5eaed08a1f/

Yang penting adalah waktu pemanggilan commandManager.InvalidateRequerySuggested. Ini harus dipanggil setelah perubahan nilai yang relevan diberitahukan.


sumber
tautan itu tidak lagi valid
Peter Duniho
-2

Di samping saran Ed Ball tentang menyetel CommandParameter sebelum Command , pastikan metode CanExecute Anda memiliki parameter tipe objek .

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

Semoga ini mencegah seseorang menghabiskan banyak waktu yang saya lakukan untuk mencari tahu cara menerima SelectedItems sebagai parameter CanExecute

Julio Nobre
sumber