【问题标题】:How to programmatically click a button in WPF?如何以编程方式单击 WPF 中的按钮?
【发布时间】:2010-10-18 05:23:31
【问题描述】:

由于 WPF 中没有 button.PerformClick() 方法,有没有办法以编程方式单击 WPF 按钮?

【问题讨论】:

    标签: c# .net wpf button


    【解决方案1】:

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

    你为什么要这样做?例如,您是在进行某种自动化测试,还是尝试执行按钮在不同代码段中执行的相同操作?

    【讨论】:

    • 这不是我的问题的唯一解决方案,但是当我尝试这样做时,我发现它并不像 button.PerformClick() 那样简单,所以有点好奇...... :)
    • 我不得不点击同一个项目中另一个窗口的菜单,而 MyOtherWindow.mnuEntry_Click(Me, New Windows.RoutedEventArgs) 做到了。真的很简单。
    【解决方案2】:

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

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

    Here 是关于该主题的博文。

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

    【讨论】:

    • Slick,我不知道这一点。对于自动化测试可能非常有用。请注意,该链接上有一条评论建议使用提供的工厂来获取自动化对等点,而不是自己创建一个。
    • 谢谢。在我添加对UIAutomationProvider 的引用之前,我一直在努力在我的应用程序中找到正确的命名空间。然后不得不添加using System.Windows.Automation.Peers; using System.Windows.Automation.Provider;
    • 斜线单线:((IInvokeProvider) (new ButtonAutomationPeer(someButton).GetPattern(PatternInterface.Invoke)).Invoke();
    • 需要注意的一点是 Invoke 调用是异步的。这意味着如果您在单元测试中使用它并且下一行是检查单击按钮的预期结果,您可能需要等待。
    • 仅供参考,IInvokeProvider接口在UIAutomationProvider程序集中定义。
    【解决方案3】:

    就像 JaredPar 所说,您可以参考 Josh Smith 的自动化文章。但是,如果您通过 cmets 阅读他的文章,您会发现针对 WPF 控件引发事件的更优雅的方式

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

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

    【讨论】:

    • RaiseEvent 解决方案仅引发事件。它不执行与按钮相关的命令(如 Skanaar 所说)
    • 如果您使用 XAML,例如 ,事件将按正常方式被 on click 处理程序捕获。来自我的 +1!
    • 我正在使用 VB...不确定 VB 和 C# 的代码是否不同,但 new RoutedEventArgs(Button.ClickEvent) 对我不起作用。我不得不使用new RoutedEventArgs(Primitives.ButtonBase.ClickEvent)。否则,效果很好!
    • 要详细说明@EduardoMolteni 和Skanaar,您将失去命令提供的IsEnabled 功能,因此除非您希望所有事件都检查它们是否已启用,否则AutomationPeer 会更好地工作。
    【解决方案4】:

    如果要调用点击事件:

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

    或使用切换按钮

    【讨论】:

      【解决方案5】:
      this.PowerButton.RaiseEvent(new RoutedEventArgs(Button.ClickEvent));
      

      【讨论】:

        【解决方案6】:

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

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

        【讨论】:

        • 这是使用子元素中的事件向父元素触发命令的好方法。
        【解决方案7】:

        MVVMButton函数使用MVVM命令模式时(推荐做法),触发Button效果的简单方法如下如下:

        someButton.Command.Execute(someButton.CommandParameter);
        

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

        【讨论】:

        • 请注意,这只会触发按钮被点击时的效果。它不会在消息调度队列中生成任何点击事件。对于所有实际情况,这是您想要的,并且会避免不必要的调度程序事件(例如,更高性能),但如果您实际上以某种方式需要调度程序事件,则上述其他解决方案更合适
        • 它节省了我的时间。
        【解决方案8】:

        自动化 API 解决方案的问题在于,它需要对框架程序集 UIAutomationProvider 的引用作为项目/包依赖项。

        另一种方法是模仿行为。下面是我的扩展解决方案,它还考虑了 MVVM 模式及其绑定命令 - 实现为 extension method

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

        【讨论】:

          【解决方案9】:

          你也可以调用按钮被点击的方法 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));

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-10-09
            • 1970-01-01
            • 2015-02-20
            • 1970-01-01
            • 2021-05-31
            • 2017-06-17
            相关资源
            最近更新 更多