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

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

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";
                }
            }
        }
    }
}

person Terrii    schedule 19.12.2012    source источник


Ответы (7)


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

person jac    schedule 19.12.2012
comment
Это правильный ответ - вызывать с делегатом, если требуется. Посмотрите раздел «Потокобезопасные вызовы элемента управления Windows Forms» в предоставленной ссылке. - person Algirdas; 19.12.2012

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

 Invoke(new Action(() => {Foo.Text="Hi";}));
person Parviz Bazgosha    schedule 19.12.2012

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

/// <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");
person SkeetJon    schedule 01.05.2014

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

 Invoke((Action)(() =>
 {
      var myVar = SomeWinFormControl.Property;
 }));
person Steve    schedule 24.10.2016

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

person Dan OConnell    schedule 19.12.2012

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

person Brian Rasmussen    schedule 19.12.2012
comment
Вам необходимо маршалировать доступ к элементу управления обратно в поток пользовательского интерфейса. Как вы вызвали DoWork? - person Brian Rasmussen; 19.12.2012
comment
при нажатии кнопки выполняется следующая команда: ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork)); - person Terrii; 19.12.2012

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

Когда вы начинаете (я предполагаю, что вы используете 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 к списку и добавьте его в свой контроль.

person Community    schedule 19.12.2012