使方法等待右键单击以转到下一步(C# 窗体)

本文关键字:下一步 窗体 等待 方法 右键 单击 | 更新日期: 2023-09-27 18:34:06

好吧,我正在编写一个机器人,它将在屏幕上使用某些坐标,然后模拟15次点击(每次点击都有不同的坐标(。我已经让它与我在代码上手动输入的坐标一起使用,但现在我需要一种方法来记录这些坐标。我想做的是:用户按下一个按钮,然后程序显示一个消息框,上面写着"右键单击主菜单",用户右键单击它,这些坐标将被记录在一个数组上,然后程序将显示第二个消息框,要求右键单击下一个按钮,如此......我的问题是我不知道如何使该方法等待用户右键单击以继续。

我通过创建一个事件来测试我的程序,该事件会在每次我右键单击并在消息框中显示坐标时触发,使用 UserActivityHook 类包含事件 OnMouseActivity:

 UserActivityHook actHook;
    void MainFormLoad(object sender, System.EventArgs e)
    {
        actHook = new UserActivityHook(); 
        // crate an instance with global hooks
        // hang on events
        actHook.OnMouseActivity+=new MouseEventHandler(MouseMoved);         
    }
    public void MouseMoved(object sender, MouseEventArgs e)
    {            
        if (e.Clicks > 0)
        {
            if (e.Button.Equals(MouseButtons.Right))
            {
                MessageBox.Show("X:" + e.X + " Y:" + e.Y);
            }
        }
    }

我尝试做这样的事情:

    private void button1_Click(object sender, EventArgs e)
    { 
        RecordMacro(cords, 1);          
    }
    public void RecordMacro(int coordinates[][], int slotnumber){
      MessageBox.show("Right click main menu");
      //saves coordinates on [0][0] and [0][1] 
      WaitForRightClickAndSaveCords(coordinates[][]);
      MessageBox.show("Right click resupply button");
      //saves coordinates on [1][0] and [1][1]
      WaitForRightClickAndSaveCords(coordinates[][]);
      ...
    }

我仍然是一个新手,这是我在StackOverflow中的第一个问题(我通常会在这里浏览找到答案,不需要问自己(,所以我很乐意接受任何批评。

使方法等待右键单击以转到下一步(C# 窗体)

这是使用 C# 5.0 的异步模型最容易实现的。 我们将首先创建一个方法,该方法将生成一个在满足条件时完成的Task。 它将通过创建一个TaskCompletionSource,向事件添加一个处理程序,并在处理程序中将任务标记为已完成来实现此目的。 加入一些样板代码以确保处理程序在完成后被删除,从完成源返回Task,我们设置:

public static Task<Point> WhenRightClicked(this UserActivityHook hook)
{
    var tcs = new TaskCompletionSource<Point>();
    MouseEventHandler handler = null;
    handler = (s, e) =>
    {
        if (e.Clicks > 0 && e.Button == MouseButtons.Right)
        {
            tcs.TrySetResult(new Point(e.X, e.Y));
            hook.OnMouseActivity -= handler;
        }
    };
    hook.OnMouseActivity += handler;
    return tcs.Task;
}

现在你可以写:

public async void RecordMacro(int[][] coordinates, int slotnumber)
{
    MessageBox.Show("Right click main menu");
    Point mainMenuPosition = await actHook.WhenRightClicked();
    MessageBox.Show("Right click resupply button");
    Point resupplyButtonPosition = await actHook.WhenRightClicked();
}

有无数种方法可以完成这项工作,您都不应该远程执行。原因是,假设您设法使用 WaitForRightClick 停止执行线程,您将阻止 UI 线程!

通过这样做,您可以阻止用户单击所需的元素(以及从不阻止 UI 线程的许多其他原因(。

你可以用线程或使用异步方法,正如 Servy 所建议的那样。这会阻止方法(或异步执行该方法(,而不会阻止 UI 线程本身。

虽然更复杂,但您也可以将一堆表示"ClickTarget"的对象排队。然后,您将侦听右键单击事件并记录与当前ClickTarget关联的坐标,取消排队以获取下一条指令,依此类推。

完整的代码对于StackOverflow来说太长了,但给你一些想法:

public class ClickTarget
{
    Point Coordinates {get; set;}
    String TargetName {get; set;}
}
Queue<ClickTarget> clickTargets;
//Obviously you instantiate/populate this somewhere
private void onRightClick(...)
{
   ClickTarget target = clickTargets.Dequeue();
   target.Coordinates = clickLocation;
   MessageBox.Show("Please click on " + clickTargets.Peek().TargetName);
}