2010-02-19 6 views
1

При запуске моей программы иногда я получаю эти исключения, иногда я этого не делаю. Это поток исполнения:System.InvalidOperationException и System.Reflection.TargetInvocationException иногда случается

Пользователь нажимает кнопку в классе Window1.
Класс собирает входы, backgroundWorker.RunWorkerAsync() запускается.
В DoWork вызывается App.doStuff().
Внутри App.doStuff(), я создаю еще одну нить, чтобы показать ProgressBar в отдельном окне, как это:

Thread newWindowThread = new Thread(new ThreadStart(showProgressMethod)); 
newWindowThread.SetApartmentState(ApartmentState.STA); 
newWindowThread.IsBackground = true; 
newWindowThread.Start(); 

В showProgressMethod(), я делаю:

progressWindow = new MyProgressWindow(this); 
progressWindow.Show(); 
System.Windows.Threading.Dispatcher.Run(); 

Теперь, если Я запускаю его в первый раз, у меня нет никаких проблем. Но когда/если я повторю операцию после ее завершения, я могу получить исключения.

Посмотрев на код, у меня возникает ощущение, что я делаю что-то неправильно, вызывая диспетчер. Run() и Thread.Start(), но я не очень хорошо разбираюсь в модели потоков, поэтому я не уверен.

В любом случае, при первом запуске программа никогда не делает ничего необычного. Но иногда, когда я снова нажимаю кнопку, чтобы активировать процесс, возникает исключение. Я думаю, что это происходит, когда программе не хватает времени на очистку? Хотя я не уверен.

EDIT

Кажется, что проблема заключается в том, что ProgressWindow нить не заканчивается. Очевидно, что добавление Thread.Abort() внутри App.doStuff() или Dispatcher.Thread.Abort() внутри ProgressWindow устраняет проблему. По всей видимости.

Но он по-прежнему вызывает исключения из-за метода Abort(), хотя он больше не сработает. Я также не понимаю, почему закрытие ProgressWindow не завершает поток. И из того, что я прочитал с помощью Thread.Abort(), не очень хорошая практика, хотя я снова не понимаю почему.

EDIT 2

Thread.Abort еще это сбой в разы. Итак, что я сделал это:
Заменить Show() призыв ShowDialog(), как это было предложено и
Удалить вызов для System.Windows.Threading.Dispatcher.Run();

ответ

0

Что находится внутри MyProgressWindow? Может быть, он обращается к некоторым ResourceDictionary дважды, один раз от первого newWindowThread, один раз от второго? ResourceDictionary s не может использоваться совместно между двумя потоками.

+0

ProgressWindow имеет ссылку на mainWindow.backgroundWorker. Событие закрытия в ProgressWindow вызывает backgroundWorker.CancelAsync() - если я закрываю ProgressWindow, я отменяю задачу. Я прокомментировал эти строки, чтобы они не делали ничего, и это не делалось. – zxcvbnm

0

a) TargetInvocationException будет реальным исключением в свойстве InnerException - проверьте это.

b) Вы уверены, что не собираетесь повторно использовать/трогать объекты из двух разных потоков? WPF явно бросает, если обнаруживает свойство зависимостей, доступ к которому осуществляется из потока, отличного от того свойства, в котором он был создан.

+0

Хорошо, когда окно progresswindow закрыто, я включаю главное окно, и когда заканчивается поток рабочего стола, я закрываю окно выполнения. поэтому я обращаюсь к другим ресурсам потоков, но я вызываю диспетчера и используя BeginInvoke, поэтому я думал, что делаю это правильно. – zxcvbnm

+0

Да, это правильный путь. Но убедитесь, что у вас есть правильный диспетчер. –

0

Пользователь нажимает кнопку в классе Window1. Класс собирает входы, запускается backgroundWorker.RunWorkerAsync(). В DoWork вызывается App.doStuff(). Внутри App.doStuff(), я создаю еще одну нить, чтобы показать ProgressBar ...

Так что теперь у вас есть код работает в потоке пользовательского интерфейса, код работает на потоке BackgroundWorker, и код, работающий на новой, третий поток, который не является потоком пользовательского интерфейса, и обновляет элементы пользовательского интерфейса. У меня есть это право? Потому что это похоже на то, что это почти наверняка проблема.

Edit:

Я удивлен, что вы делаете дела вообще, не то, что она работает непоследовательно.

ProgressChanged Событие BackgroundWorker - это то, что вы хотите использовать для взаимодействия между методом, выполняющимся в фоновом режиме и пользовательским интерфейсом. Он работает в потоке пользовательского интерфейса.

+0

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

+0

Я уже использую progresschanged для обновления progressbar в окне progresswindow. но мне все равно нужно создать третий поток, чтобы показать окно прогресса. я думаю. возможно, есть способ создать окно прогресса в том же потоке, который использует ui, а затем выполнить математику с фоном, но я не знаю. – zxcvbnm

+0

Вы можете просто Window.Show(), и он прокатится через диспетчера. Это не блокирующий звонок. ShowDialog(), однако, есть. –

Смежные вопросы