Курсор не обновляется с помощью WaitCursor с помощью задачи TPL

1

Я использую пользовательский класс (WaitCursor), чтобы гарантировать, что каждый раз, когда я запускаю длительную задачу, Cursor обновляется, чтобы показать WaitCursor. Оригинальную статью и код можно найти здесь. Внедрение класса WaitCursor. SendMessage() и GetForegroundWindow() были взяты из другого ответа здесь, в StackOverflow.

Я успешно использовал этот класс, когда использовал класс Thread для выполнения методов в отдельных потоках. Курсор был обновлен во время выполнения, а затем вернулся к умолчанию.

Затем я изменил свою логику, чтобы использовать новый класс Task из библиотеки TPL вместо 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
    Вам нужно показать нам код, если вы хотите, чтобы мы знали, что с ним не так. Вы только показали код, который вызывает код, который делает это.
  • 0
    Я обновил код и добавил класс, который я использую для управления Task / Thread .
Показать ещё 11 комментариев
Теги:
multithreading
task
cursor
task-parallel-library

1 ответ

1
Лучший ответ

Похоже, что проблема была вызвана методом DisableForm. Как-то отключение формы останавливает процесс обновления курсора.

Так что я, наконец, нашел решение, заменив DisableForm метод с DisableControls.

private void DisableControls()
{
    foreach (Control control in Controls)
    {
        control.Enabled = false;
    }
}

Остальная часть кода, поэтому класс WaitCursor и использование класса остаются неизменными:

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

Ещё вопросы

Сообщество Overcoder
Наверх
Меню