Как программно нажать кнопку в 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
Слик, я не знал об этом. Может быть очень полезно для автоматического тестирования. Обратите внимание, что в этой ссылке есть комментарий, в котором предлагается использовать предоставленную фабрику, чтобы получить одноранговый узел автоматизации, а не создавать его самостоятельно.
— Грег Д

7
Спасибо за это. Я изо всех сил пытался найти правильные пространства имен в моем приложении, пока не добавил ссылку на UIAutomationProvider. Затем пришлось добавитьusing System.Windows.Automation.Peers; using System.Windows.Automation.Provider;
— sergeantKK

5
Однострочник для наклонных:((IInvokeProvider) (new ButtonAutomationPeer(someButton).GetPattern(PatternInterface.Invoke)).Invoke();
— Дэнни Беккет

3
Следует отметить, что вызов Invoke является асинхронным. Это означает, что если вы используете его в модульном тесте, и ваша следующая строка - проверка ожидаемого результата нажатия кнопки, возможно, вам придется подождать.
— Денвер

3
Просто для справки, IInvokeProviderинтерфейс определен в UIAutomationProviderсборке.
— Стивен Рэндс

188

Как сказал JaredPar, вы можете обратиться к статье Джоша Смита, посвященной автоматизации. Однако, если вы посмотрите комментарии к его статье, вы найдете более элегантный способ поднять события против элементов управления 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 (Me, New 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

Проблема с решением Automation 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.