可以从另一个组件启动并等待表单组件的 PerformClick 吗?

问题描述 投票:0回答:1

我很难找到是否可以从另一个元素对 C# 表单元素执行虚拟单击,并等待其完成后再继续。

作为一个例子(不幸的是不完整),我想做的是这个

  private async void btn_my_Click(object sender, EventArgs e)
  {
      await Task.Run(() => radio_button_special.PerformClick()); // https://stackoverflow.com/q/14024963

      // once this is done, proceed with rest of processing
      do_rest_of_processing();
  }

当我在“调试运行”中单击按钮时,VS2019 会中断,并显示“InvalidOperationException:跨线程操作无效:从创建它的线程以外的线程访问控制‘radio_button_special’。”

但是,如果我只是在 Visual Studio 调试之外运行 exe,该按钮似乎可以工作(即我可以在应用程序中看到 radio_button_special.PerformClick() 首先完成,然后 do_rest_of_processing() 运行 - 并且我没有得到明确的像这样运行异常,所以它似乎按照我的想象工作)。

但是这个异常让我害怕,所以我想摆脱它 - 我已经尝试过像这样的补救措施,我已经尝试从 SO 上的其他片段构建:

  private async void btn_my_Click(object sender, EventArgs e)
  {
      // first, I want to call the function otherwise called
      // when the radio button is clicked, and wait for it to complete
      radio_button_special.Invoke((MethodInvoker)async delegate
      {
          await Task.Run(() => radio_button_special.PerformClick()); // https://stackoverflow.com/q/14024963
      });
      // once this is done, proceed with rest of processing
      do_rest_of_processing();
  }

现在,这个函数已经在 VS2019 IDE 中给出了警告:

警告 CS1998:此异步方法缺少“await”运算符,并将同步运行。考虑使用“await”运算符等待非阻塞 API 调用,或使用“await Task.Run(...)”在后台线程上执行 CPU 密集型工作。

...如果我调试运行该示例,我会得到堆栈跟踪:

System.Reflection.TargetInvocationException
  HResult=0x80131604
  Message=Exception has been thrown by the target of an invocation.
  Source=mscorlib
  StackTrace:
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   ...
   at System.Windows.Forms.Application.Run(Form mainForm)
   at my_test.Program.Main() in D:\work\bbs\BBS_DEV\BAPS_git\my_test\Program.cs:line 28

  This exception was originally thrown at this call stack:
    System.Windows.Forms.Control.Handle.get()
    System.Windows.Forms.Control.InternalHandle.get()
    System.Windows.Forms.Control.Update()
    System.Windows.Forms.ButtonBase.ResetFlagsandPaint()
    System.Windows.Forms.RadioButton.PerformClick()
    my_test.main_form.btn_my_Click.AnonymousMethod__122_1() in main_form.cs
    System.Threading.Tasks.Task.InnerInvoke()
    System.Threading.Tasks.Task.Execute()
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
    ...
    [Call Stack Truncated]

Inner Exception 1:
InvalidOperationException: Cross-thread operation not valid: Control 'radio_button_special' accessed from a thread other than the thread it was created on.

所以,基本上与之前的问题相同。

那么,我如何从另一个表单组件处理程序调用 C# 表单组件处理程序(例如单击)函数,等待它完成,然后调用另一个函数 - 而不会引发异常?

c# multithreading winforms asynchronous
1个回答
0
投票

Task.Run
将您提供的方法排队以在线程池线程上运行。因此,即使您执行调用,您仍然可以从另一个线程访问该控件。相反,您应该在
Control.Invoke
中调用
Task.Run

private async void button1_Click(object sender, EventArgs e)
{
    await Task.Run(() =>
    {
        radioButton1.Invoke(() => radioButton1.PerformClick());
    });
}
© www.soinside.com 2019 - 2024. All rights reserved.