如何以编程方式单击WPF中的按钮?


144

由于button.PerformClick()WPF中没有方法,是否可以通过编程方式单击WPF按钮?

Answers:


128

WPF采用的方法与WinForms略有不同。他们没有将自动化的对象内置到API中,而是为每个负责自动化的对象都有一个单独的类。在这种情况下,您需要ButtonAutomationPeer完成此任务。

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

是有关该主题的博客文章。

注意:IInvokeProvider接口是在UIAutomationProvider程序集中定义的。


2
光滑,我不知道这一点。对于自动化测试可能非常有用。请注意,在该链接上有一条评论,建议使用提供的工厂来获取自动化对等方,而不是自己创建一个。
格雷格D

7
谢谢你 在添加对的引用之前,我一直难以在应用中找到正确的名称空间UIAutomationProvider。然后不得不添加using System.Windows.Automation.Peers; using System.Windows.Automation.Provider;
sergeantKK 2014年

5
倾斜的((IInvokeProvider) (new ButtonAutomationPeer(someButton).GetPattern(PatternInterface.Invoke)).Invoke();
丹尼·贝克特

3
要注意的一件事是Invoke调用是异步的。这意味着,如果要在单元测试中使用它,而下一行是检查单击按钮的预期结果,则可能需要等待。
丹佛

3
仅供参考,该IInvokeProvider接口在UIAutomationProvider程序集中定义。
史蒂文·兰德斯

188

就像JaredPar所说的那样,您可以参考Josh Smith的有关自动化的文章。但是,如果您仔细阅读他的文章中的评论,您会发现更优雅的方式来针对WPF控件引发事件

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

我个人更喜欢上面的那种,而不是自动化的同行。


26
RaiseEvent解决方案仅引发事件。它不会执行与Button相关的命令(如Skanaar所说)
Eduardo Molteni,2010年

4
如果您使用XAML,例如<Button Name =“ X” Click =“ X_Click” />,则事件将按常规被on click处理程序捕获。向我+1!
2010年

4
我正在使用VB ...不确定该代码是否与VB相对于C#不同,但new RoutedEventArgs(Button.ClickEvent)不适用于我。我不得不用new RoutedEventArgs(Primitives.ButtonBase.ClickEvent)。否则,效果很好!
BrianVPS 2012年

3
要详细说明@EduardoMolteni和Skanaar,您将失去Commands提供的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


22
this.PowerButton.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));

5

如果您可以访问源代码,则以编程方式“单击”按钮的一种方法是简单地调用按钮的OnClick事件处理程序(或者,如果您以更WPF-y的方式执行操作,则执行与按钮关联的ICommand。 )。

你为什么做这个?例如,您是在进行某种自动化测试,还是试图从不同的代码部分执行与按钮执行的相同操作?


这不是解决我问题的唯一方法,但是当我尝试这样做时,我发现它不像button.PerformClick()那样简单,所以有点好奇……:)
tghoang

我必须单击同一项目中另一个窗口的菜单,然后MyOtherWindow.mnuEntry_Click(Me,New Windows.RoutedEventArgs)做到了。真的很简单。
Andrea Antonangeli

4

正如Greg D所说,我认为Automation使用MVVM模式(单击事件引发并执行命令)单击按钮的另OnClick一种方法是使用反射调用该方法:

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

这是使用子元素中的事件向父元素激发命令的好方法。
酷蓝

2

MVVM Command模式用于Button功能时(推荐做法),触发Button效果的简单方法如下:

someButton.Command.Execute(someButton.CommandParameter);

这将使用按钮触发的Command对象,并传递XAML定义的CommandParameter


请注意,这仅会触发单击按钮后的效果。它不会在邮件分发队列中生成任何单击事件。对于所有实际情况,这都是您所希望的,它将避免不必要的调度程序事件(例如,性能更高的人),但是如果您实际上以某种方式要求调度程序事件,则上述其他解决方案更合适
KVKConsultancy

0

Automation API解决方案的问题在于,它需要引用Framework程序集UIAutomationProvider作为项目/程序包的依赖关系。

另一种方法是模仿行为。以下是我的扩展解决方案,该解决方案还用其绑定命令对MVVM-pattern进行了调节-实现为扩展方法

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);
        }
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.