Установка проблем с текстовыми полями - PullRequest
2 голосов
/ 04 июля 2011

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

Когда я получаю сообщение, я хочу обновить текстовое поле, поэтому я использую:

txtConnectedID.Text = "test";

Но я получаю эту ошибку:

System.InvalidOperationException was unhandled by user code
  Message=Cross-thread operation not valid: Control 'txtConnectedID' accessed from a thread other than the thread it was created on.

Теперь, я думаю, это как-то связано с остановкой метода, запущенного дважды и не корректным обновлением? Я не на 100% в этом. Итак, теперь у меня есть делегат для метода, который принимает строку, и я вызываю:

private delegate void stringDelegate(string s);

BeginInvoke(new stringDelegate(writeToIPBox), new object[] { e.ConnectedIP.ToString() });

private void writeToIPBox(string newIP)
        {
            txtConnectedID.Text = newIP;
        }

Я не уверен, почему я делаю это, как это отличается. Я не очень-то счастлив, просто делаю это так, не зная, почему.

Заранее спасибо

Ответы [ 4 ]

1 голос
/ 04 июля 2011

Вы должны пытаться обновлять элементы управления только из потока, в котором они были созданы. Для этого есть веские причины, так как легко попасть в состояние гонки. Эти элементы управления не являются потокобезопасными, и это среда выполнения, которая немного вам поможет.

Вместо этого, как вы уже поняли, вам нужно обновить его в потоке пользовательского интерфейса, что и делает BeginInvoke; вызов делегата асинхронно в потоке пользовательского интерфейса.

0 голосов
/ 04 июля 2011
private static void SetText(TextBox tb, string text)
{
    if (tb.InvokeRequired)
    {
        var stDelegate = new StDelegate(SetText);
        tb.Invoke(stDelegate, new object[] { tb, text });
    }
    else
    {
        tb.Text = text;
    }
}
0 голосов
/ 04 июля 2011

Потребовались новые минуты решительного поиска в Google, но в итоге я нашел «авторитетную» ссылку:

http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired%28v=vs.90%29.aspx

Краткий ответ (чтобы процитировать эту страницу): Элементы управления в Windows Forms привязаны к определенной теме и не безопасны для потока.

Эта статья также объясняет, как это может быть обработано "внутренне" ... если control.InvokeRequired (т.е. мы были вызваны из другого потока) обрабатывают вызов внутренне ... вместо того, чтобы распространять делегаты по всему коду.

Лично я никогда не задавался вопросом, ПОЧЕМУ нужен делегат, я просто сделал это. Хороший вопрос.

Приветствия. Кит.

0 голосов
/ 04 июля 2011

Все элементы управления принадлежат потоку пользовательского интерфейса (из которых только один), и попытка доступа к ним из другого потока приводит к этому исключению.

BeginInvoke вызывает указанный делегат в потоке пользовательского интерфейса, поэтому он работает. Вы также можете проверить, находитесь ли вы в потоке пользовательского интерфейса, проверив txtConnectedID.InvokeRequired.

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