Я прочитал много вопросов SO, связанных с BackgroundWorker и DispatcherTimer, и понимаю, что вы не можете получить доступ к компонентам пользовательского интерфейса ни в каком потоке, кроме основного.
Итак, у меня есть DispatcherTimer, который тикает каждые 1/2 секунды. Как и следовало ожидать, я могу обновить класс модели представления и любой элемент пользовательского интерфейса, который требует прямых манипуляций, и пользовательский интерфейс довольно отзывчивый. Однако у меня есть расчет, основанный на значении в пользовательском интерфейсе, выполнение которого занимает около 3 секунд.
Я попытался просто выполнить вычисление в потоке DispatcherTimer, и это заблокировало / заблокировало пользовательский интерфейс до его завершения. В настоящее время у меня есть проверка в DispatcherTimer, которая затем запускает поток BackgroundWorker, который запускается и выполняет расчет. Я использую e.Arguments, чтобы передать моему 3-секундному вычислительному процессу необходимые данные и e.Result для завершенных данных, которые я получаю.
Я проверил результат, ошибок нет. Однако, когда я возвращаю e.Result обратно в свой класс, e.Result не может правильно оцениваться. Когда я использую свойство class, я получаю сообщение «вызывающий поток не может получить доступ к ошибке».
...
timerBackgroundLoop = new DispatcherTimer(DispatcherPriority.Background);
timerBackgroundLoop.Interval = TimeSpan.FromMilliseconds(500);
timerBackgroundLoop.Tick += new EventHandler(Timer_Tick);
timerBackgroundLoop.Start();
...
private void Timer_Tick(object sender, EventArgs e)
{
if (MyClass.NeedToRebuildBuildMap)
{
MyClass.NeedToRebuildBuildMap = false; //stop next timer tick from getting here
threadDrawMap = new BackgroundWorker();
threadDrawMap.WorkerReportsProgress = false;
threadDrawMap.WorkerSupportsCancellation = false;
threadDrawMap.DoWork += new DoWorkEventHandler(threadDrawMap_DoWork);
threadDrawMap.RunWorkerCompleted += new RunWorkerCompletedEventHandler(threadDrawMap_Completed);
threadDrawMap.RunWorkerAsync(myClass.MapData);
}
...
}
private void threadDrawMap_DoWork(object sender, DoWorkEventArgs e)
{
MyClass.MapData _mapData = (MyClass.MapData)e.Argument;
e.Result = BuildMap(_mapData);
}
private void threadDrawMap_Completed(object sender, RunWorkerCompletedEventArgs e)
{
MyClass.MapGeo = (List<PathGeometry>)e.Result;
DrawUIMap(MyClass.MapGeo); //draws the map on the UI into a grid
}
Когда я устанавливаю перерыв в «threadDrawMap_Completed» и оцениваю List of PathGeometry, я получаю эту ошибку: base {System.SystemException} = {"Вызывающий поток не может получить доступ к этому объекту, потому что он принадлежит другому потоку."}
На самом деле я не вижу ошибки, пока не использую метод DrawUIMap и не пытаюсь получить доступ к списку геометрии MyClass.MapGeo. На этом этапе я снова в потоке DispatcherTimer, который может получить доступ к пользовательскому интерфейсу.
Насколько я знаю, я все сделал правильно, насколько и где / когда я обращаюсь к компонентам пользовательского интерфейса. Хотя мне кажется, что я где-то сделал что-то ужасно не так.
** Изменить: это часть кода, который выполняет расчет.
public static List<PathGeometry> BuildMap(List<PathGeometry> _geoList)
{
...
List<PathGeometry> retGeoList = new List<PathGeometry>();
retGeoList.Add(geoPath1);
retGeoList.Add(geoPath2);
...
return retGeoList;
}
MyClass.NeedToRebuildBuildMap
, я не уверен, но использование флага вtimer
для предотвращения запуска следующегоBackgroundWoker
может быть не лучшим вариантом? может быть шанс, что флаг будет сброшен, и прежде, чем он будет установлен наFalse
, дваTimer tick
сработают .. - person Bolu   schedule 09.10.2013