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

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

147390 次浏览

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

你为什么要这么做?例如,您是否正在进行某种类型的自动化测试,或者尝试执行按钮从不同代码段执行的相同操作?

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

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

这里 是一篇关于这个主题的博客文章。

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

就像 JaredPar 说的,你可以参考 Josh Smith 关于自动化的文章。然而,如果你浏览他的文章的评论,你会发现更优雅的方式提出反对 WPF 控件的事件

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

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

如果要调用 click 事件:

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 });

或者使用切换按钮

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

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

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

当对 按钮函数使用 MVVM Command 模式时(推荐的做法) ,触发 按钮效应的简单方法如下:

someButton.Command.Execute(someButton.CommandParameter);

这将使用按钮触发的 命令对象并传递由 XAML定义的 命令参数

自动化 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);
}
}
}

您还可以调用按钮被单击的方法 Button_Click(new object(), new RoutedEventArgs(ButtonBase.ClickEvent)); 另一种方式是 ButtonName.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent)); 两种方式都需要 using System.Windows.Controls.Primitives;

  • Button_Click(new object(), new RoutedEventArgs(ButtonBase.ClickEvent));
  • ButtonName.RaiseEvent(new RoutedEventArgs(ButtonBase.ClickEvent));