WinForms - 从单独的线程启用 AsyncCallback 上的按钮

WinForms - Enable button on AsyncCallback from a separate thread

我对多线程非常陌生,所以我确信我的整个问题很可能是错误的,但这更多的是让我了解如何正确完成事情,所以我希望你能原谅和任何设置在 "idiot" 水平的解释将不胜感激!!!!

假设我的 WinForm 外部有以下 class:

public class test
{
    public void RunOnSeparateThread()
    {
        // Some function that takes an AsyncCallback as a parameter and runs Asynchronously
        // Returns IAsyncResult
        foo(m_asyncCallback);
    }

    private AsyncCallback m_asyncCallback = new AsyncCallback(AsyncComplete);
    private static void AsyncComplete(IAsyncResult result)
    { 
        // Whatever disposal stuff needs to be done, etc.
    }
}

现在,我想做的是在我的 winform 上有一个按钮,按下时:

  1. 禁用按钮
  2. 在单独的线程上运行 RunOnSeparateThread 进程(不占用 GUI 线程)

然后,当异步过程完成时:

  1. Testclass
  2. 中有AsyncComplete方法运行
  3. 重新启用表单上的按钮(也许 Form class 中还有其他一些东西)

正如我所说,这对我来说都是全新的。我想象可以做的是在表单上创建一个 AsyncCallback 委托并将其传递给我的 class(作为 属性??)并使用 AsyncComplete 方法 运行 最后,但看起来这可能是非常糟糕的编程。

执行此操作的最佳/正确方法是什么 - 请理解我是这类东西的主要新手,所以我非常感谢任何链接/解释以了解正确的多方法 -像这样的场景的线程。

此外,虽然这是用 C# 编写的,但我对 VB 和 C# 都同样满意,所以任何答案都将不胜感激。

谢谢!!!

我建议您使用 TPL instead of outdated APM approach unless your requirements are to use old .Net framework versions. But back to the question. Most UI frameworks don't allow UI modification from non-main (non-UI) thread. So, you should use Invoke method to post updates to the UI thread loop (or BeginInvoke 以异步方式执行委托)。使用 TPL 一切都非常简单:

void button_Click(object sender, EventArgs e)
{
    button.Enabled = false;
    Task.Factory.StartNew(() =>
    {
        //long-running stuff
    }).ContinueWith((result) =>
    {
        button.Enabled = true;
    }, TaskScheduler.FromCurrentSynchronizationContext());
}

另请注意,您问的问题实际上过于宽泛,最好阅读WinForms.

中有关以异步方式执行任务的文章

编辑

如果您无法控制 foo,您的代码可能如下所示:

void button_Click(object sender, EventArgs e)
{
    button.Enabled = false;
    IAsyncResult asyncResult = foo(...);
    Task.Factory.FromAsync(asyncResult, (result) =>
    {
        button.Enabled = true;
    }, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
}