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...
}