WPF - Bir Komutu, CommandBindings aracılığıyla 'CanExecute'u yeniden değerlendirmeye zorlama


130

Bir var Menuher yerde MenuItemhiyerarşisinde onun etmiştir Commandtesiste ayarlı RoutedCommandben tanımladık. İlişkili CommandBinding, değerlendirme için CanExecuteher birinin etkin durumunu kontrol eden bir geri arama sağlar MenuItem.

Bu neredeyse çalışıyor. Menü öğeleri başlangıçta doğru etkinleştirilmiş ve devre dışı bırakılmış durumlarla gelir. Ancak CanExecutegeri aramamın kullandığı veriler değiştiğinde, bu yeni durumun kullanıcı arayüzüne yansıtılması için geri aramamdan bir sonucu yeniden isteme komutuna ihtiyacım var.

Bunun üzerine RoutedCommandveya bunun CommandBindingiçin herhangi bir kamuya açık yöntem görünmüyor .

Denetime tıkladığımda veya yazdığımda geri aramanın tekrar kullanıldığını unutmayın (sanırım girişte tetikleniyor çünkü fareyle üzerine gelme yenilemeye neden olmaz).

Yanıtlar:


172

Kitaptaki en güzel şey değil, ancak tüm komut bağlamayı geçersiz kılmak için CommandManager'ı kullanabilirsiniz:

CommandManager.InvalidateRequerySuggested();

MSDN hakkında daha fazla bilgi görün


1
Teşekkürler, bu gayet iyi çalıştı. Kullanıcı arayüzünde ufak bir gecikme var, ancak bunun için çok endişelenmiyorum. Ayrıca cevabınızı derhal yukarı oyladım, sonra işe yarayıp yaramadığını görmek için oylamayı geri aldım. Artık işe yaradığına göre, oylamayı tekrar uygulayamam. SO'nun neden bu kuralı uyguladığından emin değilim.
Drew Noakes

5
Oyumu yeniden uygulamak için cevabınızı düzenledim. Düzenlemede hiçbir şeyi değiştirmedim. Tekrar teşekkürler.
Drew Noakes

Bir Texbox'ın içeriğini arka koddan değiştirirken de aynı sorunu yaşadım. El ile düzenlerseniz işe yarayacaktır. Bu uygulamada, metin kutusu açılan bir denetim tarafından düzenleniyordu ve açılır pencereyi kaydettiğinizde Texbox.Text özelliğini değiştiriyordu. Bu sorunu çözdü! Teşekkürler @Arcturus
Dzyann

10
Diğer yanıtı not edin ( stackoverflow.com/questions/783104/refresh-wpf-command ) "UI iş parçacığında çağrılması gerekir"
Samvel Siradeghyan

84

Bununla daha sonra karşılaşan herkes için; MVVM ve Prism kullanıyorsanız, Prism'in DelegateCommanduygulaması bunu yapmak için ICommandbir .RaiseCanExecuteChanged()yöntem sağlar .


12
Bu model, diğer MVVM kitaplıklarında da bulunur, örneğin MVVM Light.
Peter Lillevold

2
Prism'den farklı olarak, MVVM Light v5'in kaynak kodu RaiseCanExecuteChanged() basit çağrılarını gösterir CommandManager.InvalidateRequerySuggested().
Peter

4
WPF'de MVVM Light için bir yan not, GalaSoft.MvvmLight.CommandWpf ad alanını kullanmanız gerekir çünkü GalaSoft.MvvmLight.Command sorun yaratır mvvmlight.net/installing/changes#v5_0_2
fuchs777

((RelayCommand)MyCommand).RaiseCanExecuteChanged();GalaSoft.MvvmLight.Command kullanarak benim için çalıştı - AMA değiştirdikten sonra CommandWPF, hiçbir şey aramaya gerek kalmadan çalıştı. Teşekkürler @ fuchs777
Robin Bennett

1
Ya bir 3. taraf kitaplığı kullanmıyorsanız?
Vidar

28

Kullanamadım CommandManager.InvalidateRequerySuggested();çünkü performans vuruluyordum.

Aşağıdaki gibi görünen MVVM Yardımcısı'nın Temsilci komutunu kullandım (ihtiyacımız için biraz ayarladım). command.RaiseCanExecuteChanged()sanal makineden aramanız gerekiyor

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
Sadece bir Bilginize CommandManager.RequerySuggested + = value; Bazı nedenlerden dolayı CanExecute kodumun neredeyse sabit / döngüsel bir değerlendirmesini alıyordum. Aksi takdirde çözüm beklendiği gibi çalıştı. Teşekkürler!
robaudas

16

Uygulayan kendi sınıfınızı oluşturduysanız ICommand, sizi manuel yenilemeye gerekenden daha fazla güvenmeye zorlayan birçok otomatik durum güncellemesini kaybedebilirsiniz. Ayrıca kırılabilir InvalidateRequerySuggested(). Sorun, basit bir ICommanduygulamanın yeni komutu CommandManager.

Çözüm, aşağıdakileri kullanmaktır:

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

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

Bu şekilde aboneler CommandManagersınıfınıza bağlanır ve komut durumu değişikliklerine uygun şekilde katılabilir.


2
Basit, isabetli ve insanların kendi ICommand uygulamaları üzerinde kontrol sahibi olmalarına izin veriyor.
Akoi Meexx

2

Komutlara özellik bağımlılığını işlemek için bir çözüm uyguladım, burada bağlantı https://stackoverflow.com/a/30394333/1716620

bunun sayesinde şu şekilde bir komuta sahip olacaksınız:

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

Benim için işe yarayan şey buydu: CanExecute'u XAML'de Komutun önüne koyun.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.