События Background Worker - PullRequest
       22

События Background Worker

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

псевдокод:

form1
{
    int i;
    label1;

    Add()
    {
     i++;
     label1 = i.ToString(); //#ErrorLine
    }

    backgroundworker worker;

    worker_DoWork()
    { 
     FileGuard guard = new FileGuard();
     guard.FileKilled += guard.KillH(Add);
     guard.StarGuarding(); //there is system watcher inside 
                           //this guard and some processing code
                           //that will fire event FileKilled();

    } 
} 

После вызова StartGuarding () рабочий будет завершен Но когда происходит событие FileKilled, я получаю эту ошибку в строке # ErrorLine

Операция между потоками недопустима: доступ к элементу управления form1 осуществляется из потока, отличного от потока, в котором он был создан.

Ответы [ 4 ]

4 голосов
/ 02 января 2011

Это не имеет ничего общего с самими событиями, а скорее связано с тем, что вы обращаетесь к элементам управления пользовательского интерфейса из другого потока.В Windows Forms вам не разрешено взаимодействовать с пользовательским интерфейсом из какого-либо другого потока, кроме основного потока пользовательского интерфейса.

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

private void DoStuffWithGUI() 
{
    if (InvokeRequired) 
    {
        Action work = DoStuffWithGUI;
        Invoke(work);
    }
    else
    {
        // Your normal logic
    }
}

Пользовательский интерфейс можно использовать непосредственно из ProgressChanged и RunWorkerCompletedEvents (поскольку они автоматически направляются в поток пользовательского интерфейса).Но вся работа, которую вы выполняете в DoWork (и, следовательно, все события, которые вы можете вызывать как часть работы), выполняется в отдельном потоке и должна быть направлена ​​в поток пользовательского интерфейса с помощью Invoke.Из MSDN для BackgroundWorker :

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

2 голосов
/ 02 января 2011

Это потому, что третий поток используется, когда FileKilled вызывается системой.

Что касается BackgroundWorker, вы должны использовать события для обработки обновлений GUI: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

0 голосов
/ 02 января 2011

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

private readonly _lockObject = new Object();

Add()
{
     lock(_lockObject)
     {
         i++;
         if(label1.InvokeRequired)
             Invoke(new Action( () => label1 = i.ToString()));
         else
             label1 = i.ToString();
     }
}

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

0 голосов
/ 02 января 2011

Вы не можете получить доступ к Windows Forms или объектам WPF из чего-либо, кроме формы, в которой они были созданы, отсюда ваша проблема.

Используйте диспетчера для отправки обновления обратно в ваш поток пользовательского интерфейса.

Если вы можете подробно рассказать, используете ли вы WinForms или WPF, мы можем предоставить дополнительную информацию.

...