Як програмно натиснути кнопку в WPF?


144

Оскільки button.PerformClick()у WPF немає методу, чи є можливість програмно натиснути кнопку WPF?

Відповіді:


128

WPF використовує дещо інший підхід, ніж WinForms тут. Замість того, щоб автоматизація об'єкта була вбудована в API, вони мають окремий клас для кожного об'єкта, який відповідає за його автоматизацію. У цьому випадку вам потрібно ButtonAutomationPeerвиконати це завдання.

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

Ось допис у блозі на цю тему.

Примітка: IInvokeProviderінтерфейс визначений у UIAutomationProviderзбірці.


2
Slick, я не знав цього. Може бути дуже корисним для автоматизованого тестування. Зауважте, що до цього посилання є коментар, який пропонує використовувати надану фабрику, щоб отримати одноранговий аналог, а не створювати його самостійно.
Грег Д

7
Дякую за це Я намагався знайти правильні простори імен у своєму додатку, поки не додав посилання на UIAutomationProvider. Потім довелося додатиusing System.Windows.Automation.Peers; using System.Windows.Automation.Provider;
сержантKK

5
Однолінійний нахил для схильних:((IInvokeProvider) (new ButtonAutomationPeer(someButton).GetPattern(PatternInterface.Invoke)).Invoke();
Danny Beckett

3
Варто зазначити, що виклик Invoke є асинхронним. Це означає, що якщо ви використовуєте його в одиничному тесті, а ваш наступний рядок - це перевірити очікуваний результат натискання кнопки, можливо, доведеться почекати.
денвер

3
Тільки для довідки, IInvokeProviderінтерфейс визначений в UIAutomationProviderзборі.
Стівен Рандс

188

Як сказав ДжаредПар, ви можете звернутися до статті Джоша Сміта щодо автоматизації. Однак якщо ви подивитесь на коментарі до його статті, ви знайдете більш елегантний спосіб підняття подій проти контролю WPF

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

Я особисто віддаю перевагу тому, що вище, а не колегам з автоматизації.


26
Рішення RaiseEvent лише викликає подію. Він не виконує команду, пов’язану з кнопкою (як кажуть Сканаар)
Едуардо Молтені

4
Якщо ви використовуєте XAML, наприклад, <Button Name = "X" Click = "X_Click" />, подія буде зафіксована за допомогою обробника клацання, як правило. +1 від мене!
метао

4
Я використовую VB ... не впевнений, чи відрізняється код для віршів VB C #, але new RoutedEventArgs(Button.ClickEvent)не працював для мене. Мені довелося користуватися new RoutedEventArgs(Primitives.ButtonBase.ClickEvent). Інакше чудово працює!
BrianVPS

3
Щоб детальніше ознайомитися з @EduardoMolteni та Skanaar, ви втрачаєте функцію IsEnabled, надану командами таким чином, тому, якщо ви не хочете, щоб усі ваші події перевірили, чи вони включені, AutomationPeer працює краще.
Джастін Піхоні

34

якщо ви хочете зателефонувати події кліку:

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

А якщо ви хочете, щоб кнопка виглядала так, як її натискають:

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

і не стиснуте після цього:

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

або скористатися кнопкою ToggleButton



5

Один із способів програмно "натиснути" на кнопку, якщо у вас є доступ до джерела, - це просто викликати обробник подій OnClick кнопки (або Виконати ICommand, пов'язаний з цією кнопкою, якщо ви робите речі більш WPF-y способом ).

Чому ви це робите? Ви робите, наприклад, автоматичне тестування, або намагаєтесь виконати ту саму дію, яку виконує кнопка з іншого розділу коду?


Це не єдине рішення моєї проблеми, але коли я спробував це зробити, я виявив, що це не так просто, як button.PerformClick (), тож трохи цікаво ... :)
tghoang

Мені довелося натиснути меню іншого вікна того ж проекту, і MyOtherWindow.mnuEntry_Click (Мене, Нова Windows.RoutedEventArgs) це зробив. Дійсно просто.
Андреа Антонангелі

4

Як сказав Грег Д , я думаю, що альтернативою Automationнатискання кнопки за допомогою шаблону MVVM (подія натискання піднята і команда виконується) - викликати OnClickметод за допомогою відображення:

typeof(System.Windows.Controls.Primitives.ButtonBase).GetMethod("OnClick", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(button, new object[0]);

Це хороший спосіб використовувати подію з дочірнього елемента для запуску команди на батьків.
Прохолодний синій

2

При використанні шаблону команд MVVM для функції кнопки (рекомендована практика) простий спосіб викликати ефект кнопки полягає в наступному:

someButton.Command.Execute(someButton.CommandParameter);

Для цього буде використаний об'єкт Command, який запускає кнопку і передасть CommandParameter, визначений XAML .


Одне зауваження, це лише запускає ефект, який буде мати кнопку, якщо її натиснути. Він не генерує жодних подій клацання в черзі відправлення повідомлень. Для всіх практичних випадків саме цього ви хочете, і уникнете зайвих диспетчерських подій (наприклад, більш ефективних), але якщо ваші фактично потрібні диспетчерські події, інші рішення вище є більш підходящими
KVKConsultancy

0

Проблема з рішенням API автоматизації полягає в тому, що воно вимагало посилання на складання Framework UIAutomationProviderяк залежність проекту / пакета.

Альтернативою є наслідування поведінки. Далі є моє розширене рішення, яке також обумовлює MVVM-зразок із пов'язаними командами - реалізований як метод розширення :

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);
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.