Как программно нажать кнопку в 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.