C# 使用TPL任务未使用WaitCursor更新游标

C# 使用TPL任务未使用WaitCursor更新游标,c#,multithreading,cursor,task-parallel-library,task,C#,Multithreading,Cursor,Task Parallel Library,Task,我正在使用一个自定义类(WaitCursor)来确保每次运行长时间运行的任务时,光标都会更新以显示WaitCursor。原始文章和代码可以在这里找到。SendMessage()和getforegroundindow()是从StackOverflow的另一个答案中获取的 当我使用Thread类在单独的线程上执行方法时,我成功地使用了这个类。光标在执行过程中被更新,然后恢复为默认值 然后我改变了逻辑,使用TPL库中新的Task类,而不是Thread,现在光标不再更新,我总是看到默认光标 在代码中没有

我正在使用一个自定义类(
WaitCursor
)来确保每次运行长时间运行的任务时,
光标
都会更新以显示
WaitCursor
。原始文章和代码可以在这里找到。
SendMessage()
getforegroundindow()
是从StackOverflow的另一个答案中获取的

当我使用
Thread
类在单独的线程上执行方法时,我成功地使用了这个类。光标在执行过程中被更新,然后恢复为默认值

然后我改变了逻辑,使用TPL库中新的
Task
类,而不是
Thread
,现在光标不再更新,我总是看到默认光标

在代码中没有进行其他更改。当使用
线程时,对我的类中创建新
任务的方法的每次调用都与以前相同

下面是我的代码

这是
TaskManager
,我用来管理
任务执行的类。ThreadManager是前一个共享完全相同逻辑的类。唯一的区别在于对创建新的
线程
/
任务
的方法的调用,因此
线程.Start()
/
任务.Factory.StartNew()

WaitCursor
class

public class WaitCursor : IDisposable
{
    public WaitCursor()
    {
        Enabled = true;
    }

    public void Dispose()
    {
        Enabled = false;
    }

    public static bool Enabled
    {
        get
        {
            return Application.UseWaitCursor;
        }

        set
        {
            if (value == Application.UseWaitCursor) return;
            Application.UseWaitCursor = value;
            Cursor.Current = value ? Cursors.WaitCursor : Cursors.Default;
            var handle = GetForegroundWindow();
            SendMessage(handle, 0x20, handle, (IntPtr)1); // Send WM_SETCURSOR
            Cursor.Position = Cursor.Position; // Trick to update the cursor even if the user doesn't move the mouse
        }
    }

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);

    [System.Runtime.InteropServices.DllImport("user32.dll")]
    private static extern IntPtr GetForegroundWindow();
}
MyMethod
实现

private void MyMethod()
{
    using (new WaitCursor())
    {
        // Do something that takes long time...
    }
}
我唯一改变的是
Task
而不是
Thread
,它对我的方法和
EventHandler
也是透明的

线程
和TPL
任务
在管理游标更新方面有什么区别

更新1

正如@JimMischel所建议的,我尝试使用
Invoke
方法而不是
UseWaitCursor
类,但它不起作用。这是代码

private void btnLogin_Click(object sender, EventArgs e)
{
    // Start a new Task for MyMethod
    _taskManager.StartNewTask(MyMethod);
}

private void MyMethod()
{
    Invoke((MethodInvoker) DisableForm);
    Invoke((MethodInvoker) ToggleWaitCursor);

    // Do something that takes long time...

    Invoke((MethodInvoker) EnableForm);
    Invoke((MethodInvoker) ToggleWaitCursor);
}

private void ToggleWaitCursor()
{
    if (this.UseWaitCursor)
        this.UseWaitCursor = false;
    else
        this.UseWaitCursor = true;
}

private void DisableForm()
{
    this.Enabled = false;
}

private void EnableForm()
{
    this.Enabled = true;
}

问题似乎是由于
禁用表单
方法造成的。以某种方式禁用表单会停止光标更新过程

因此,我最终找到了一个解决方案,用
DisableControls
替换
DisableForm
方法

private void DisableControls()
{
    foreach (Control control in Controls)
    {
        control.Enabled = false;
    }
}
代码的其余部分,因此
WaitCursor
类和类的用法保持不变:

using (new WaitCursor())
{
    // Do something that takes long time...
}

如果你想让我们知道代码出了什么问题,你需要给我们看一下代码。您只显示了调用执行此操作的代码的代码。我更新了代码并添加了用于管理
任务
/
线程
的类。这行代码似乎是
Cursor.Position=Cursor。Position
在非UI线程中执行有点危险。我很惊讶它没有抛出异常。一个区别是
线程默认情况下创建一个前台线程。
任务
在池线程上执行,池线程是后台线程。不过,我真的认为这在这里并不重要。想一想,你能不能只做一个
调用
来设置光标,并摆脱复杂的
WaitCursor
逻辑?复制别人的代码时需要正确的属性。@HansPassant是的,你是对的!我忘了!那是文章:。我也在原来的问题上加了。
private void DisableControls()
{
    foreach (Control control in Controls)
    {
        control.Enabled = false;
    }
}
using (new WaitCursor())
{
    // Do something that takes long time...
}