Bagaimana cara mengklik tombol di WPF?

144

Karena tidak ada button.PerformClick()metode dalam WPF, apakah ada cara untuk mengklik tombol WPF secara terprogram?

tghoang
sumber

Jawaban:

128

WPF mengambil pendekatan yang sedikit berbeda dari WinForms di sini. Alih-alih memiliki otomatisasi objek yang dibangun ke dalam API, mereka memiliki kelas terpisah untuk setiap objek yang bertanggung jawab untuk mengotomatisasi itu. Dalam hal ini Anda perlu ButtonAutomationPeermenyelesaikan tugas ini.

ButtonAutomationPeer peer = new ButtonAutomationPeer(someButton);
IInvokeProvider invokeProv = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;
invokeProv.Invoke();

Berikut adalah posting blog tentang masalah ini.

Catatan: IInvokeProviderantarmuka didefinisikan dalam UIAutomationProvidermajelis.

JaredPar
sumber
2
Slick, saya tidak menyadari hal ini. Dapat sangat berguna untuk pengujian otomatis. Perhatikan bahwa ada komentar di tautan yang menyarankan menggunakan pabrik yang disediakan untuk mendapatkan rekan otomatisasi alih-alih membuatnya sendiri.
Greg D
7
Terima kasih untuk ini. Saya kesulitan menemukan ruang nama yang benar di aplikasi saya, sampai saya menambahkan referensi UIAutomationProvider. Kemudian harus menambahkanusing System.Windows.Automation.Peers; using System.Windows.Automation.Provider;
sersanKK
5
Satu kalimat untuk yang condong:((IInvokeProvider) (new ButtonAutomationPeer(someButton).GetPattern(PatternInterface.Invoke)).Invoke();
Danny Beckett
3
Satu hal yang perlu diperhatikan adalah bahwa panggilan Invoke tidak sinkron. Itu berarti jika Anda menggunakannya dalam unit test dan baris Anda berikutnya adalah untuk memeriksa hasil yang diharapkan dari mengklik tombol, Anda mungkin harus menunggu.
denver
3
Hanya untuk referensi, IInvokeProviderantarmuka didefinisikan dalam UIAutomationProvidermajelis.
Steven Rands
188

Seperti yang dikatakan JaredPar, Anda dapat merujuk ke artikel Josh Smith tentang Otomasi. Namun jika Anda melihat melalui komentar di artikelnya, Anda akan menemukan cara yang lebih elegan untuk meningkatkan acara terhadap kontrol WPF

someButton.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));

Saya pribadi lebih suka yang di atas daripada rekan-rekan otomatisasi.

Denis Vuyka
sumber
26
Solusi RaiseEvent hanya memunculkan acara. Itu tidak mengeksekusi Perintah yang terkait dengan Button (seperti yang dikatakan Skanaar)
Eduardo Molteni
4
Jika Anda menggunakan XAML misalnya <Tombol Nama = "X" Klik = "X_Klik" />, acara akan ditangkap oleh penangan klik saat seperti biasa. +1 dari saya!
metao
4
Saya menggunakan VB ... tidak yakin apakah kodenya berbeda untuk ayat VB C #, tetapi new RoutedEventArgs(Button.ClickEvent)tidak berhasil untuk saya. Saya harus menggunakan new RoutedEventArgs(Primitives.ButtonBase.ClickEvent). Kalau tidak, bekerja dengan baik!
BrianVPS
3
Untuk menguraikan @EduardoMolteni dan Skanaar, Anda kehilangan fungsionalitas IsEnabled yang diberikan oleh Perintah dengan cara ini, jadi kecuali jika Anda ingin semua acara Anda memeriksa apakah mereka diaktifkan, AutomationPeer bekerja lebih baik.
Justin Pihony
34

jika Anda ingin memanggil acara klik:

SomeButton.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));

Dan jika Anda ingin tombolnya terlihat seperti ditekan:

typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(SomeButton, new object[] { true });

dan tidak terbuka setelah itu:

typeof(Button).GetMethod("set_IsPressed", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(SomeButton, new object[] { false });

atau gunakan ToggleButton

Sonorx
sumber
22
this.PowerButton.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
Mahdi
sumber
5

Salah satu cara untuk secara programatik "mengklik" tombol, jika Anda memiliki akses ke sumbernya, adalah dengan hanya memanggil pengendali event OnClick tombol (atau Jalankan ICommand yang terkait dengan tombol, jika Anda melakukan hal-hal dengan cara yang lebih WPF-y ).

Mengapa kau melakukan ini? Apakah Anda melakukan semacam pengujian otomatis, misalnya, atau mencoba melakukan tindakan yang sama dengan yang dilakukan tombol dari bagian kode yang berbeda?

Greg D
sumber
Ini bukan satu-satunya solusi untuk masalah saya, tetapi ketika saya mencoba untuk melakukan hal ini, saya menemukan bahwa itu tidak semudah button.PerformClick (), jadi hanya sedikit penasaran ... :)
tghoang
Saya harus mengklik pada menu jendela lain dalam proyek yang sama, dan MyOtherWindow.mnuEntry_Click (Saya, Windows Baru. RuteEventArgs) melakukannya. Sangat sederhana.
Andrea Antonangeli
4

Seperti yang dikatakan Greg D , saya berpikir bahwa alternatif untuk Automationmengklik tombol menggunakan pola MVVM (klik acara yang dibangkitkan dan perintah dieksekusi) adalah memanggil OnClickmetode menggunakan refleksi:

typeof(System.Windows.Controls.Primitives.ButtonBase).GetMethod("OnClick", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(button, new object[0]);
Maks
sumber
Ini adalah cara yang baik untuk menggunakan suatu peristiwa dari elemen anak untuk memecat suatu perintah pada orangtua.
Cool Blue
2

Saat menggunakan pola Perintah MVVM untuk fungsi Tombol (praktik yang disarankan), cara sederhana untuk memicu efek Tombol adalah sebagai berikut:

someButton.Command.Execute(someButton.CommandParameter);

Ini akan menggunakan objek Command yang dipicu tombol dan melewati CommandParameter yang ditentukan oleh XAML .

KVKConsultancy
sumber
Satu catatan, ini hanya memicu efek tombol jika diklik. Itu tidak menghasilkan peristiwa klik dalam antrian pengiriman pesan. Untuk semua kasus praktis, inilah yang Anda inginkan dan akan menghindari acara dispatcher yang tidak perlu (mis. Lebih banyak performan) tetapi jika Anda sebenarnya membutuhkan event dispatcher solusi lain di atas lebih tepat
KVKConsultancy
0

Masalah dengan solusi API Otomatisasi adalah, bahwa diperlukan referensi ke perakitan Kerangka UIAutomationProvidersebagai ketergantungan proyek / paket.

Alternatifnya adalah meniru perilaku. Berikut ini adalah solusi saya yang diperluas yang juga menghubungkan pola-MVVM dengan perintah terikat - diimplementasikan sebagai metode ekstensi :

public static class ButtonExtensions
{
    /// <summary>
    /// Performs a click on the button.<br/>
    /// This is the WPF-equivalent of the Windows Forms method "<see cref="M:System.Windows.Forms.Button.PerformClick" />".
    /// <para>This simulates the same behaviours as the button was clicked by the user by keyboard or mouse:<br />
    /// 1. The raising the ClickEvent.<br />
    /// 2.1. Checking that the bound command can be executed, calling <see cref="ICommand.CanExecute" />, if a command is bound.<br />
    /// 2.2. If command can be executed, then the <see cref="ICommand.Execute(object)" /> will be called and the optional bound parameter is p
    /// </para>
    /// </summary>
    /// <param name="sourceButton">The source button.</param>
    /// <exception cref="ArgumentNullException">sourceButton</exception>
    public static void PerformClick(this Button sourceButton)
    {
        // Check parameters
        if (sourceButton == null)
            throw new ArgumentNullException(nameof(sourceButton));

        // 1.) Raise the Click-event
        sourceButton.RaiseEvent(new RoutedEventArgs(System.Windows.Controls.Primitives.ButtonBase.ClickEvent));

        // 2.) Execute the command, if bound and can be executed
        ICommand boundCommand = sourceButton.Command;
        if (boundCommand != null)
        {
            object parameter = sourceButton.CommandParameter;
            if (boundCommand.CanExecute(parameter) == true)
                boundCommand.Execute(parameter);
        }
    }
}
rittergig
sumber