Почему метод StatusBar.Invoke не работает для ToolStripProgressBar? - PullRequest
0 голосов
/ 05 октября 2011

Недавно я работал над приложением, в котором я хотел отображать ход выполнения другого потока в строке состояния с помощью элемента управления ToolStripProgressBar, который содержится в элементе управления StatusBar.До того, как я попытался добавить этот код, у меня изначально был код, изменяющий текст элемента управления ToolStripStatusLabel, и для этого я использовал метод Invoke с делегатами, и все работало нормально.Тем не менее, я обнаружил, что когда я пытался сделать это с помощью ToolStripProgressBar, вызов метода Invoke в строке состояния завершился неудачно без уведомления (без ошибок, без исключений, ничего).С тех пор я узнал, что для использования индикатора выполнения таким образом я должен был использовать элемент управления BackgroundWorker.Итак, мой код работает, но я не понимаю, почему я не смог использовать метод Invoke, который, похоже, уже работал.

Некоторые примеры того, что сработало, а что нет:

Это сработало

 public delegate void changeStatusMessage(String message);
 public changeStatusMessage changeStatusMessageDelegate;
 public void changeStatusMessageMethod(String message){
      if(statusbar.InvokeRequired){
           statusbar.Invoke(changeStatusMessageDelegate, new Object[] {message});
      }else{
           toolstripLabel.Text = message;
      }
 }

Это не сработало

 public delegate void incrementProgressBar(int value);
 public incrementProgressBar incrementProgressBarDelegate;
 public void incrementProgressBarMethod(int value){
      if(statusbar.InvokeRequired){
           statusbar.Invoke(incrementProgressBarDelegate, new Object[] {value});
      }else{
           toolstripProgress.Increment(value);
      }
 }

В примере, который не сработал, свойство InvokeRequired имеет значение true, поэтому вызывается метод Invoke, а затем ничегослучается.Где, как я и ожидал, на этот раз снова вызовем incrementProgressBarMethod, где InvokeRequired ложно и, таким образом, разрешает запуск метода Increment.

Мне бы очень хотелось узнать, почему это не работает.Как я уже сказал, я уже переустанавливал на использование BackgroundWorker, мне просто нужно объяснение.

1 Ответ

0 голосов
/ 01 июля 2013

Invoke вызывает API postmessage и ставит сообщение в очередь в сообщении Windows.Если поток пользовательского интерфейса заблокирован, то вы можете зайти в тупик, поскольку он не может выдвинуть сообщение в очереди, ничего не произойдет.Другая необходимая сторона вызова не запускается, и если что-то ее ждет, взрыв, тупик.

Это причина, по которой вам нужно быть осторожным с Invoke.

Как вызвать функцию в родительском потоке в .NET?

Но ваша проблема заключается в создании делегата, это нулевой делегат, вам нужно создатьделегат в том же потоке, который вызывается с помощью invoke, потому что в другом случае подчиненная система не сможет маршалировать делегат (его указатель).

    private void changeStatusMessageMethod(String message)
    {
        if (this.InvokeRequired)
        {
            var changeStatusMessageDelegate = new changeStatusMessage(changeStatusMessageMethod);
            this.Invoke(changeStatusMessageDelegate, new Object[] { message });
        }
        else
        {
            toolstripLabel.Text = message;
        }
    }
    delegate void incrementProgressBar(int value);
    private void incrementProgressBarMethod(int value)
    {
        if (this.InvokeRequired)
        {
            var incrementProgressBarDelegate = new incrementProgressBar(incrementProgressBarMethod);
            this.Invoke(incrementProgressBarDelegate, new Object[] { value });
        }
        else
        {
            toolstripProgress.Increment(value);
        }
    }

Работает на dotnet framework v4

    private void button1_Click(object sender, EventArgs e)
    {
        var t = new System.Threading.Thread(new System.Threading.ThreadStart(x));
        t.Start();
    }

    private void x()
    {
        do
        {
            changeStatusMessageMethod(DateTime.Now.ToString());
            System.Threading.Thread.Sleep(1000);
        } while (true);
    }

    private void button2_Click(object sender, EventArgs e)
    {
        var t = new System.Threading.Thread(new System.Threading.ThreadStart(y));
        t.Start();
    }

    private void y()
    {
        do
        {
            incrementProgressBarMethod(1);
            System.Threading.Thread.Sleep(1000);
        } while (true);
    }
...