• [WPF] PerformClick ?


                                          [WPF] PerformClick ? 

                                                     周银辉

    WPF没有提供这个方法,还真是让人觉得有些讨厌啊。而关于这个嘛,Google中搜一下,一大堆,但一般是利用XXXAutomationPeer。

    这个原本用于支持自动化测试的,被拿来干了这事,代码如下:

            public static void PerformClick(this Button button)
            {
                var peer 
    =new ButtonAutomationPeer(button);

                var invokeProv 
    = peer.GetPattern(PatternInterface.Invoke) as IInvokeProvider;

                
    if (invokeProv != null)
                {
                    invokeProv.Invoke();
                }
            }

     
    但很快地,你会发现去其依赖于具体的类:ButtonAutomationPeer, 所以WPF实现了一堆XXXAutomationPeer, 这多少让人觉得有些.... 比如“我想在任意UI元素上模拟下鼠标点击”,这种方法便不可行了,虽然有一堆Peer,再多也不是“任意”,那么用SendMessage吧,这才是王道,代码如下:

            public static void PerformClick(this UIElement element, Point point)
            {
                var window 
    = Window.GetWindow(element);

                
    if (window != null)
                {
                    var windowHwnd 
    = GetHwnd(window);

                    var locOfElement 
    = element.TranslatePoint(new Point(00), window);
                    var pointToWindow 
    = new Point(point.X + locOfElement.X, point.Y + locOfElement.Y);

                    Int32 lparam 
    = MakeLong((int)pointToWindow.X, (int)pointToWindow.Y);

                    
    // WM_LBUTTONDOWN = 0x0201
                    SendMessage(windowHwnd, WM_LBUTTONDOWN, 0, lparam);
                    
    // WM_LBUTTONUP = 0x0202;
                    SendMessage(windowHwnd, WM_LBUTTONUP, 0, lparam);
                }
            }

            
    internal static int MakeLong(int lowWord, int highWord)
            {
                
    return (highWord << 16| (lowWord & 0xffff);
            }

            
    internal static IntPtr GetHwnd(this Window window)
            {
                var winHelper 
    = new WindowInteropHelper(window);
                
    return winHelper.Handle;
            }

     这个方法可以拓展到任意UI元素上,但很奇怪的是:居然不会引发Button的Click事件!从效果上看,的确点击了,因为焦点都转移上去了。那好吧,再用用下面的方法吧:反射,我比较喜欢这个方式:

            public static void PerformClick(this ButtonBase button)
            {
                var method 
    = button.GetType().GetMethod("OnClick"
                    BindingFlags.NonPublic 
    | BindingFlags.Instance);

                
    if (method != null)
                {
                    method.Invoke(button, 
    null);
                }

                
    //button.Focus();
            }

    OK,总结一下:
    第一种方法,依赖于具体的XXXPeer, 能力有限,不够灵活

    第二种方法,较灵活,但由于SendMessage第一个参数要求传入hwnd,而WPF普通控件没有句柄,所以其依赖于窗口句柄,也就是该方法依赖窗口

    第三种方法,我喜欢。有什么缺点吗?如果没有,为啥Google上的朋友们都用第一种方法?如果有,是啥?

    -----------------------

    [update]

    最近看到一个开源项目, 专门模拟键盘和鼠标,非常棒: http://inputsimulator.codeplex.com/

    源代码打包下载 : https://files.cnblogs.com/zhouyinhui/WindowsInput.zip  

    使用方法嘛,比如:

     var sim = new InputSimulator();
     sim.Mouse.LeftButtonDown();

  • 相关阅读:
    Java 回调函数的理解
    Java对象初始化
    Hibernate中get方法和load方法的区别
    Java 如何判断导入表格某列是否有重复数据
    Java学习之Java的单例模式
    Java中怎么设置文件权限
    div居中问题
    JSON
    js
    ajax
  • 原文地址:https://www.cnblogs.com/zhouyinhui/p/1740111.html
Copyright © 2020-2023  润新知