Почему я получаю эту ошибку: «Недопустимая операция между потоками: доступ к элементу управления lbFolders осуществляется из потока, отличного от потока, в котором он был создан.»? - PullRequest
2 голосов
/ 28 октября 2008

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

prgAll.Maximum = lbFolders.SelectedItems.Count;
Я получаю ошибку. Тем не менее, вот часть, которую я не понимаю. Если я закомментирую эту строку, самая следующая строка
foreach (string dir in lbFolders.SelectedItems)
выполняется просто отлично.

Edit: Как обычно, мои коммуникативные навыки отсутствуют. Позвольте уточнить.

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

Мой вопрос был в основном такой: Почему я могу обращаться к объекту SelectedItems и выполнять итерации по нему, но когда я пытаюсь получить (не установить) его свойство Count, оно взрывается.

Ответы [ 7 ]

18 голосов
/ 28 октября 2008

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

например.

lblStatus.Invoke((Action)(() => lblStatus.Text = counter.ToString()));

или старше skool:

lblTest.Invoke((MethodInvoker)(delegate() 
{ 
  lblTest.Text = i.ToString(); 
}));

У меня есть запись в блоге о том, как это сделать во всех версиях .Net здесь .

6 голосов
/ 28 октября 2008
prgAll.Maximum = lbFolders.SelectedItems.Count;

В этой строке вы выполняете присваивание ( set / add ), которое по умолчанию не является поточно-ориентированным.

Во второй строке это просто операция get , где безопасность потоков просто не имеет значения.

РЕДАКТИРОВАТЬ: я не имею в виду доступ к элементу prgAll.

Доступ к свойству Count изменяет внутреннее состояние внутренней коллекции ListBox, поэтому он вызывает исключение.

3 голосов
/ 28 октября 2008

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

2 голосов
/ 28 октября 2008

Вы пытаетесь записать в элемент управления поток, отличный от основного потока. Используйте Invoke или BeginInvoke.

void SetMax()
{
    if (prgAll.InvokeRequired)
    {
        prgAll.BeginInvoke(new MethodInvoker(SetMax));
        return;
    }

    prgAll.Maximum = lbFolders.SelectedItems.Count;
}
1 голос
/ 28 октября 2008

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

private void RunMe()
{
    if (!InvokeRequired)
    {
        myLabel.Text = "You pushed the button!";
    }
    else
    {
        Invoke(new ThreadStart(RunMe));
    }
}
1 голос
/ 28 октября 2008

Вы не можете прикоснуться к объекту GUI из потока, который не является основным потоком GUI. См. здесь для получения более подробной информации и решения.

0 голосов
/ 12 декабря 2014

Попробуйте это:

private delegate void xThreadCallBack();
private void ThreadCallBack()
{
    if (this.InvokeRequired)
    {
        this.BeginInvoke(new xThreadCallBack(ThreadCallBack));
    }
    else
    {
        //do what you want
    }
}

Хотя ответа с лямбда-выражением было бы достаточно.

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