我正在使用自定义类(WaitCursor
)来确保每次运行长时间运行的任务时,Cursor
都会更新以显示WaitCursor
。可以在Implementing a WaitCursor Class找到原始文章和代码。 SendMessage()
和GetForegroundWindow()
来自 StackOverflow 的另一个答案here。
当我使用Thread
类在不同的线程上执行方法时,我成功地使用了这个类。游标在执行期间更新,然后恢复为默认值。
然后我更改了逻辑以使用 TPL库中的新Task
类而不是Thread
,现在光标不再更新,我总是看到默认值光标。
代码中没有其他更改。在使用Task
时,每次调用我的类创建新Thread
的方法都与以前相同。
以下是我的代码。
这是TaskManager
,我用来管理Task
执行的类。 ThreadManager是前一个具有完全相同逻辑的类。唯一的区别在于调用创建新Thread
/ Task
的方法,因此Thread.Start()
/ Task.Factory.StartNew()
。
public class TaskManager
{
private static readonly TaskManager Instance = new TaskManager();
private readonly Dictionary<int, Task> _tasksList;
private static int _tasksCount;
private TaskManager()
{
_tasksList = new Dictionary<int, Task>();
_tasksCount = 0;
}
public static TaskManager GetInstance()
{
return Instance;
}
public int StartNewTask(Action method)
{
try
{
Task task = Task.Factory.StartNew(method);
_tasksCount++;
_tasksList.Add(task.Id, task);
return task.Id;
}
catch (Exception ex)
{
// Manage exception and log error
}
return -1;
}
}
致电创建Thread
/ Task
private void btnOK_Click(object sender, EventArgs e)
{
// Before, using Thread class
_threadManager.StartNewThread(MyMethod);
// Now, using Task class
_taskManager.StartNewTask(MyMethod);
}
WaitCursor
上课
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
也是透明的。
在Thread
和TPL Task
之间管理游标更新有何不同?
更新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;
}
答案 0 :(得分:1)
问题似乎是branch(foo)
方法造成的。以某种方式禁用表单会停止游标更新过程。
所以我终于找到了一个解决方案用DisableForm
取代 DisableForm
方法。
DisableControls
代码的其余部分,所以private void DisableControls()
{
foreach (Control control in Controls)
{
control.Enabled = false;
}
}
类和类的用法保持不变:
WaitCursor