Label.Text = Struct.Value (Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException) - PullRequest
1 голос
/ 09 января 2011

У меня есть приложение, над которым я работаю при опросах от интернет-провайдера (квота на скачивание).Я пытался проделать это через 'new Thread (ThreaProc)', но это не сработало, сейчас пытаюсь использовать подход на основе IAsyncResult, который делает то же самое ... Я понятия не имею, как исправить, пожалуйста, помогите?

Нужно знать:

// Global
public delegate void AsyncPollData(ref POLLDATA pData);

// Class scope:
private POLLDATA pData;

private void UpdateUsage()  
{  
  AsyncPollData PollDataProc = new AsyncPollData(frmMain.PollUsage);  
  IAsyncResult result = PollDataProc.BeginInvoke(ref pData,  
    new AsyncCallback(UpdateDone), PollDataProc);  
}

public void UpdateDone(IAsyncResult ar)
{
  AsyncPollData PollDataProc = (AsyncPollData)ar.AsyncState;
  PollDataProc.EndInvoke(ref pData, ar);
  // The Exception occurs here:
  lblStatus.Text = pData.LastError;
}

public static void PollUsage(ref POLLDATA PData)
{
  PData.LastError = "Some string";
  return;
}

Ответы [ 5 ]

3 голосов
/ 09 января 2011

Вы можете создать себе новый класс и создать расширения, например:

public static class ThreadSafeHelpers {
        public static void SetText(this Label varLabel, string newText) {
            if (varLabel.InvokeRequired) {
                varLabel.BeginInvoke(new MethodInvoker(() => SetText(varLabel, newText)));
            } else {
                varLabel.Text = newText;
            }
        }
}

И затем вы можете использовать это в любом месте своего кода, например:

lblStatus.SetText(pData.LastError);

Вы можете создать несколькоаналогичные расширения для других вещей, таких как CheckBox, RadioButtons в том же классе.Таким образом, вы можете легко запомнить и использовать методы расширения.

Конечно, вы также можете создать обычный метод, подобный этому (обратите внимание на отсутствие this рядом с меткой):

public static class ThreadSafeHelpers {
        public static void SetText(Label varLabel, string newText) {
            if (varLabel.InvokeRequired) {
                varLabel.BeginInvoke(new MethodInvoker(() => SetText(varLabel, newText)));
            } else {
                varLabel.Text = newText;
            }
        }
}

и используйте такой код:

ThreadSafeHelpers.SetText(varLabel, newText);
3 голосов
/ 09 января 2011
lblStatus.Invoke(delegate() { lblStatus.Text = pData.LastError; });

Обновление значений между потоками небезопасно, поэтому компилятор предупреждает вас. При использовании Invoke() переданный код будет вызываться в потоке GUI, поэтому вы обновляете значение GUI в потоке GUI, что безопасно.

1 голос
/ 09 января 2011

Ваш элемент управления был создан в потоке A [Тот, который рисует и обрабатывает сообщения Windows], поэтому поток B [Монитор] не может получить к нему доступ [Ура для условий гонки], взгляните на это:

Как обновить графический интерфейс из другого потока в C #?

Приветствия

0 голосов
/ 14 мая 2013

Метод Sleep Thread может работать для вас

                Thread.Sleep(100);
                this.Invoke((MethodInvoker)delegate
                {

                    txtChatBox.Text += msgReceived.strMessage + "\r\n";
                });
0 голосов
/ 09 января 2011

[Дополнительные примечания: я использую .NET 3.0]

Даже когда я использую метод, описанный в «Как обновить графический интерфейс из другого потока в C #?»другие части этой функции (UpdateDone) не работают (даже части, которые не имеют ничего общего с многопоточностью, не работают, потому что некоторые части класса были доступны вне текущего потока).

// This now works
DelegationClass.SetPropertyThreadSafe(lblStatus, () => lblStatus.Text, pData.LastError);
// Later on down the function, both objects are a member of the same class, the variable icon was never touched by another thread.
this.Icon = icon;
// An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll
// Additional information: Cross-thread operation not valid: Control 'frmMain' accessed from a thread other than the thread it was created on.

Исправьте меня, если я 'Это неправильно, но поскольку вызывается EndInvoke, поток должен был прерваться.Поэтому не должно быть никаких «условий гонки»;все данные снова принадлежат первичному потоку, и я могу свободно делать с данными то, что я хочу ...?

В этой структуре есть несколько элементов, которые я использую во всем классе;Есть ли лучший способ сделать это?Как бы вы это сделали?

Основные ограничения:
* Отдельная функция выполняет опрос данных, идея не состоит в том, чтобы блокировать взаимодействие с пользовательским интерфейсом.
* Поэтому эта функция должна быть асинхронной
* Основной класс Form (frmMain) должен быть уведомлен (Async) о завершении рассматриваемой функции и, при необходимости, обновить ее GUI.
* И, конечно, прежде всего, данные, полученные функцией, должны быть легкодоступно для членов frmMain

(Боже, с C ++ многопоточность была намного проще)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...