Обновите C # Chart с помощью BackgroundWorker - PullRequest
4 голосов
/ 13 января 2011

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

bwCharter.RunWorkerAsync(chart1);

, который работает:

private void bcCharter_DoWork(object sender, DoWorkEventArgs e)
{
     System.Windows.Forms.DataVisualization.Charting.Chart chart = null;

     // Convert e.Argument to chart
     //..
     // Converted..

     chart.Series.Clear();
     e.Result=chart;

     setChart(c.chart);
}
private void setChart(System.Windows.Forms.DataVisualization.Charting.Chart arg)
{
     if (chart1.InvokeRequired)
     {
         chart1.Invoke(new MethodInvoker(delegate { setChart(arg); }));
         return;
     }

     chart1 = arg;
}

Однако в точке очисткисерия, исключение.

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

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

Интересно, что диаграмма находится на закладке.Я могу запускать это снова и снова, если вкладка находится в фоновом режиме, но если я запускаю это, смотрю на график, скрываю его снова и снова запускаю, выдает исключение.Очевидно, он выдает, если диаграмма также находится на переднем плане.

Кто-нибудь может подсказать, что я могу сделать по-другому?

Спасибо!


РЕДАКТИРОВАТЬ: Я знаючто это можно сделать в потоке формы, как при повторном назначении.Однако весь смысл использования фонового работника состоит в том, чтобы избежать остановки всей программы.Как я уже сказал, обработка намного больше, чем просто одна команда.

Я предполагал, что передача его в качестве аргумента позволит мне беспрепятственно получить доступ к нему в этом потоке, но есть ли шанс, что эта переданная диаграммавсе еще указывает на исходный график каким-то образом?Если так, как это можно преодолеть?

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

Ответы [ 4 ]

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

Если вы хотите сначала очистить его, а затем выполнить много асинхронной работы, прежде чем снова его отобразить, почему бы вам не позвонить chart.Series.Clear();, прежде чем вызывать BackgroundWorker? В этом случае он очищается в основном потоке пользовательского интерфейса, затем вы выполняете асинхронную работу перед тем, как снова установить диаграмму из потока пользовательского интерфейса.

Кроме того, при использовании BackgroundWorker я бы использовал встроенные события ReportProgress и WorkerCompleted, чтобы избежать ручного многопоточного вызова. Это одна из причин использования BackgroundWorker в первую очередь для получения такого рода функциональности для "free" . Поэтому настройку диаграммы следует выполнить в WorkerCompleted, чтобы упростить ваш код (даже если это не является источником проблемы в данном случае).

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

Я согласен с анализом в предыдущих постах: вы просите поток получить доступ к ресурсу другого потока.
Как вы использовали BackgroundWorker, я предлагаю вам использовать Dispatcher:

private void bcCharter_DoWork(object sender, DoWorkEventArgs e)
{
    Chart chart = null;

    Dispatcher.Invoke(DispatcherPriority.Normal,
        new Action(() =>
            {
                chart.Series.Clear();
            }));
}
1 голос
/ 13 января 2011

Проверьте, требуется ли вызов в bcCharter_DoWork, если да, поместите вызов метода Clear и в делегата.

 if (InvokeRequired)
 {          

     Invoke(new MethodInvoker(delegate 
     { 
       chart.Series.Clear();
       e.Result=chart;               
     }));

     return;
 }
0 голосов
/ 13 января 2011

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

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

...