Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Межпоточная операция недействительна в Windows Forms

Автор вопроса: TerriiОтветов: 7

Может ли кто-нибудь помочь мне, у меня проблема. Я пытаюсь заставить этот код работать в фоновом режиме через пул потоков, но я не могу заставить его работать, я продолжаю получать эту ошибку:

Cross-thread operation not valid: Control 'ListBox3' accessed
from a thread other than the thread it was created on.

Вот код, который я использую:

private void DoWork(object o)
{
    var list = ListBox3;

    var request = createRequest(TxtServer.Text, WebRequestMethods.Ftp.ListDirectory);

    using (var response = (FtpWebResponse)request.GetResponse())
    {
        using (var stream = response.GetResponseStream())
        {
            using (var reader = new StreamReader(stream, true))
            {
                while (!reader.EndOfStream)
                {
                    list.Items.Add(reader.ReadLine());
                    ResultLabel.Text = "Connected";
                }
            }
        }
    }
}

invokewinformsftpthreadpool

Ответы

Ответ 1 · рейтинг 6 · jac

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

Ответ 2 · рейтинг 9 · Parviz Bazgosha

Вы можете получить доступ к управлению, сделав это

 Invoke(new Action(() => {Foo.Text="Hi";}));

Ответ 3 · рейтинг 3 · SkeetJon

Этот метод расширения также решает проблему.

/// <summary>
/// Allows thread safe updates of UI components
/// </summary>
public static void InvokeEx<T>(this T @this, Action<T> action) where T : ISynchronizeInvoke
{
    if (@this.InvokeRequired)
    {
        @this.Invoke(action, new object[] { @this });
    }
    else
    {
        action(@this);
    }
}

Используйте в своем рабочем потоке следующим образом

InvokeEx(x => x.MyControl.Text = "foo");

Ответ 4 · рейтинг 3 · Steve

Вы также можете получить доступ к элементам управления с помощью вызова, используя следующий синтаксис с делегатом действия:

 Invoke((Action)(() =>
 {
      var myVar = SomeWinFormControl.Property;
 }));

Ответ 5 · рейтинг 2 · Dan OConnell

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

Ответ 6 · рейтинг 1 · Brian Rasmussen

Я предполагаю, что DoWork запускается в другом потоке. Код обращается к элементу ListBox3, который является элементом управления с графическим интерфейсом. .NET ограничивает доступ к элементам управления GUI тем потоком, который их создал.

Ответ 7 · рейтинг 1 · Community

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

Когда вы начинаете (я предполагаю, что вы используете BackgroundWorker), передайте URL-адрес из текстового поля в RunWorkerAsync(TxtServer.Text) в качестве аргумента, затем:

private void DoWork(object o, DoWorkEventArgs e)
{
    string Url = (string) e.Argument;

    List<of string> tmpList = new List<of string>;

    var request = createRequest(url, WebRequestMethods.Ftp.ListDirectory);

    using (var response = (FtpWebResponse)request.GetResponse())
    {
        using (var stream = response.GetResponseStream())
        {
            using (var reader = new StreamReader(stream, true))
            {
                while (!reader.EndOfStream)
                {
                    list.Add(reader.ReadLine());
                    //ResultLabel.Text = "Connected";
                    //use reportprogress() instead
                }
            }
        }
    }
    e.result = tmpList;
}

Затем в своем событии Completed приведите e.result к списку и добавьте его в свой контроль.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы