Страницы

Поиск по вопросам

пятница, 14 февраля 2020 г.

Как эмулировать нажатие на кнопку в приложении WPF C#

#c_sharp #wpf #button


Подскажите, как в приложении WPF эмулировать программно нажатие на кнопку Button
левой клавишей мыши?
Использовать button1.PerformClick() не предлагать, в WPF нет такого метода у Button.
    


Ответы

Ответ 1



Способ 1: this.button.RaiseEvent(new RoutedEventArgs(Button.ClickEvent)); Способ 2: typeof(System.Windows.Controls.Primitives.ButtonBase) .GetMethod("OnClick", BindingFlags.Instance | BindingFlags.NonPublic) .Invoke(button, new object[0]); Пример: public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private void button_Click(object sender, RoutedEventArgs e) { MessageBox.Show("КНОПКА НАЖАТА"); } private void button1_Click(object sender, RoutedEventArgs e) { this.button.RaiseEvent(new RoutedEventArgs(Button.ClickEvent)); } private void button2_Click(object sender, RoutedEventArgs e) { typeof(System.Windows.Controls.Primitives.ButtonBase).GetMethod("OnClick", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(button, new object[0]); } }

Ответ 2



В шаблоне кнопки есть элемент ButtonChrome (называется Chrome), нажатие по кнопке с помощью триггера выставляет свойство RenderPressed этого элемента в значение true. Вы можете добавить кнопке Attached Property и переопределить ее шаблон, в котором добавить еще один триггер на установку этого AP. Более простой, но менее изящный способ — наследоваться от кнопки и выставить публичный метод для ее нажатия: class MyButton : Button { public async void PressAsync() { var chrome = GetTemplateChild("Chrome") as Decorator; if (chrome == null) return; var chromeType = chrome.GetType(); var propertyInfo = chromeType.GetProperty("RenderPressed"); propertyInfo.SetValue(chrome, true); await Task.Delay(100); propertyInfo.SetValue(chrome, false); } } Я здесь использовал рефлексию, т.к. ButtonChrome может использоваться из разных сборок (зависит от ОС и от ее темы). Использование: Кодбихайнд: private void TextBox_TextChanged(object sender, TextChangedEventArgs e) { MB.PressAsync(); } Другой, еще более костыльный способ — использовать вместо обычной кнопки переключатель ToggleButton: class MyButton : ToggleButton { protected override async void OnChecked(RoutedEventArgs e) { base.OnChecked(e); await Task.Delay(100); IsChecked = false; } } При нажатии кнопки в поле ввода просто установите ему IsChecked = true, через 0,1 с он "откинется" автоматически: private void TextBox_TextChanged(object sender, TextChangedEventArgs e) { MB.IsChecked = true; }

Ответ 3



Есть еще вот такой способ: using System; using System.Collections.Generic; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Input; using System.Windows.Interop; using System.IO; using System.Xml; using System.Runtime.InteropServices; using System.Threading.Tasks; namespace WpfApplication1 { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } /*Вспомогательные методы и константы...*/ public static Point ElementPointToScreenPoint(UIElement element, Point pointOnElement) { return element.PointToScreen(pointOnElement); } [DllImport("user32.dll")] static extern int GetSystemMetrics(int smIndex); [DllImport("user32.dll")] static extern uint SendInput(uint nInputs, [MarshalAs(UnmanagedType.LPArray), In] INPUT[] pInputs, int cbSize); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] static extern bool GetCursorPos(ref Win32Point pt); const uint MOUSEEVENTF_ABSOLUTE = 0x8000; const uint MOUSEEVENTF_MOVE = 0x0001; const uint MOUSEEVENTF_LEFTDOWN = 0x0002; const uint MOUSEEVENTF_LEFTUP = 0x0004; const int SM_CXSCREEN = 0; const int SM_CYSCREEN = 1; /* Эмулирует нажатие мышью на элемент управления */ public static async void PerformClick(Control ctrl) { double XSCALEFACTOR = 65535.0 / (GetSystemMetrics(SM_CXSCREEN) - 1); double YSCALEFACTOR = 65535.0 / (GetSystemMetrics(SM_CYSCREEN) - 1); //находим координаты центра элемента double x = ctrl.ActualWidth / 2; double y = ctrl.ActualHeight / 2; Point p = ElementPointToScreenPoint(ctrl, new Point(x, y)); //сохраняем текущие координаты мыши Win32Point mouse = new Win32Point(); GetCursorPos(ref mouse); //эмулируем нажатие INPUT[] arr = new INPUT[1]; arr[0].Type = INPUT_TYPE.INPUT_MOUSE; arr[0].Data.Mouse.ExtraInfo = IntPtr.Zero; arr[0].Data.Mouse.X = (int)Math.Round(p.X * XSCALEFACTOR); arr[0].Data.Mouse.Y = (int)Math.Round(p.Y * YSCALEFACTOR); arr[0].Data.Mouse.Flags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE | MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP; var res =SendInput(1, arr, Marshal.SizeOf(typeof(INPUT))); if(!Window.GetWindow(ctrl).IsMouseOver) await Task.Delay(1); //если мышь за пределами окна, WPF понадобится некоторое время для обработки события //возвращаем предыдущее положение мыши arr[0].Type = INPUT_TYPE.INPUT_MOUSE; arr[0].Data.Mouse.X = (int)Math.Round(mouse.X * XSCALEFACTOR); arr[0].Data.Mouse.Y = (int)Math.Round(mouse.Y * YSCALEFACTOR); arr[0].Data.Mouse.Flags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_MOVE ; res = SendInput(1, arr, Marshal.SizeOf(typeof(INPUT))); } private async void Window_Loaded(object sender, RoutedEventArgs e) { //пример использования await Task.Delay(1000); PerformClick(button1); await Task.Delay(3000); PerformClick(button2); } } //WINAPI types... enum INPUT_TYPE : uint { INPUT_MOUSE = 0, INPUT_KEYBOARD = 1, INPUT_HARDWARE = 2 } [StructLayout(LayoutKind.Sequential)] struct INPUT { public INPUT_TYPE Type; public MOUSEKEYBDHARDWAREINPUT Data; } [StructLayout(LayoutKind.Explicit)] struct MOUSEKEYBDHARDWAREINPUT { [FieldOffset(0)] public HARDWAREINPUT Hardware; [FieldOffset(0)] public KEYBDINPUT Keyboard; [FieldOffset(0)] public MOUSEINPUT Mouse; } [StructLayout(LayoutKind.Sequential)] struct HARDWAREINPUT { public uint Msg; public ushort ParamL; public ushort ParamH; } [StructLayout(LayoutKind.Sequential)] struct KEYBDINPUT { public ushort Vk; public ushort Scan; public uint Flags; public uint Time; public IntPtr ExtraInfo; } [StructLayout(LayoutKind.Sequential)] struct MOUSEINPUT { public int X; public int Y; public uint MouseData; public uint Flags; public uint Time; public IntPtr ExtraInfo; } [StructLayout(LayoutKind.Sequential)] struct Win32Point { public Int32 X; public Int32 Y; }; }

Комментариев нет:

Отправить комментарий