我的WPF程序将多个CSV文件中的数据加载到折线图中(每个文件都放入其自己的LineSeries中)。这需要一些时间(使GUI无法使用),所以我想在一个单独的线程中执行此操作并显示加载消息(来自Extended WPF Toolkit的BusyIndicator)。
不幸的是,当我尝试在BackgroundWorker中创建LineSeries时,我得到一个例外:“调用线程必须是STA,因为许多UI组件都需要这个。”我正在尝试复制GUI的图表,填充副本,然后在完成后将其复制到GUI的图表中。所以这不应该尝试从不同的线程访问控件。
/// <summary>
/// Loads data from the collections into the chart
/// </summary>
private void populateChart()
{
// Begin working: Pass chart and data to the worker (wrapped in a class)
this.chartWorker.RunWorkerAsync(new ChartWorkerArgs()
{
chart = chart,
data = model.getAllCollections()
});
}
/// <summary>
/// Populates a provided Chart with provided data.
/// </summary>
private void chartWorker_DoWork(object sender, DoWorkEventArgs e)
{
// ...
// Iterate through each one
foreach (XYCollection collection in data)
{
// Create a new LineSeries and configure it
LineSeries ls = new LineSeries(); // <-----------ERROR
ls.ItemsSource = collection;
ls.IndependentValueBinding = new Binding("X");
ls.DependentValueBinding = new Binding("Y");
ls.Title = collection.Name;
chart.Series.Add(ls);
}
// Send the pouplated chart back
e.Result = chart;
}
/// <summary>
/// After chart has been populated (or cancelled), update chart.
/// </summary>
private void chartWorker_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
// ...
// Set the GUI's chart as the newly populated chart
this.chart = (Chart)e.Result;
// ...
}
/// <summary>
/// Loads data from the collections into the chart
/// </summary>
private void populateChart()
{
// Begin working: Pass chart and data to the worker (wrapped in a class)
this.chartWorker.RunWorkerAsync(new ChartWorkerArgs()
{
chart = chart,
data = model.getAllCollections()
});
}
/// <summary>
/// Populates a provided Chart with provided data.
/// </summary>
private void chartWorker_DoWork(object sender, DoWorkEventArgs e)
{
// ...
// Iterate through each one
foreach (XYCollection collection in data)
{
// Create a new LineSeries and configure it
LineSeries ls = new LineSeries(); // <-----------ERROR
ls.ItemsSource = collection;
ls.IndependentValueBinding = new Binding("X");
ls.DependentValueBinding = new Binding("Y");
ls.Title = collection.Name;
chart.Series.Add(ls);
}
// Send the pouplated chart back
e.Result = chart;
}
/// <summary>
/// After chart has been populated (or cancelled), update chart.
/// </summary>
private void chartWorker_RunWorkerCompleted(
object sender, RunWorkerCompletedEventArgs e)
{
// ...
// Set the GUI's chart as the newly populated chart
this.chart = (Chart)e.Result;
// ...
}
从我在其他地方读到的内容来看,它不可能成为一个BackgroundWorker STA,那么还有其他方法可以在不挂起GUI的情况下使用数据加载图表吗?
由于
答案 0 :(得分:2)
您不应该从后台工作者访问UI元素。 WPF UI(几乎)是单线程的。这意味着您必须在后台线程中加载数据,并更新UI调用UI线程中所需的函数(使用Dispatcher.Invoke)。
所以基本上你必须在你的后台线程中做所有必要的(和冗长的)数据准备(无论你是使用BackgroundWorker
还是其他任何一个多线程设备都没关系,但是创建UI元素的维护和视觉状态的维护必须Invoke
进入主线程。
Here你可以找到一个简单的例子。
答案 1 :(得分:0)
您可以使用普通线程。然后你有控制权(所有权)使其成为STA。
Bgw添加了一些方便的功能来与GUI交互,没有什么是你自己不能用几行代码编写的。你甚至没有使用UpdateProgress。