问题
I'm currently recoding a bar chart in my app to make use of the Chart
class in the WPF Toolkit. Using MVVM, I'm binding the ItemsSource
of a ColumnSeries
in my chart to a property on my viewmodel. Here's the relevant XAML:
<charting:Chart>
<charting:ColumnSeries ItemsSource="{Binding ScoreDistribution.ClassScores}"
IndependentValuePath="ClassName" DependentValuePath="Score"/>
</charting:Chart>
And the property on the viewmodel:
// NB: viewmodel derived from Josh Smith's BindableObject
public class ExamResultsViewModel : BindableObject
{
// ...
private ScoreDistributionByClass _scoreDistribution;
public ScoreDistributionByClass ScoreDistribution
{
get
{
return _scoreDistribution;
}
set
{
if (_scoreDistribution == value)
{
return;
}
_scoreDistribution = value;
RaisePropertyChanged(() => ScoreDistribution);
}
}
However, when I update the ScoreDistribution
property (by setting it to a new ScoreDistribution
object), the chart gets an additional series (based on the new ScoreDistribution) as well as keeping the original series (based on the previous ScoreDistribution).
To illustrate this, here are a couple of screenshots showing the chart before an update (with a single data point in ScoreDistribution.ClassScores
) and after it (now with 3 data points in ScoreDistribution.ClassScores
):
Now, I realise there are other ways I could be doing this (e.g. changing the contents of the original ScoreDistribution
object rather than replacing it entirely), but I don't understand why it's going wrong in its current form. Can anyone help?
回答1:
I had the same problem. When changing the ItemsSource of a DataPointSeries it happened that old DataPoints were not removed from the chart.
My workaround in the WPF Toolkit (DataPointSeries.cs)...
A for
instead of a foreach
loop in LoadDataPoints()
, because we change the collection:
for (int i = oldItems.Count - 1; i >= 0; i--)
Change the if
in OnDataPointStateChanged()
to:
if (dataPoint.State == DataPointState.Hidden || dataPoint.State == DataPointState.PendingRemoval)
This way the DataPoint will be immediately removed.
Edit:
I also had to disable the DataPoint animation, described here.
回答2:
The most simple way to avoid this problem is to bind the serie ItemSource with IsAsync to True.
ItemsSource="{Binding DataItems, IsAsync=True}"
回答3:
Turns out the problem was triggered by the frequency of updates in the chart, not the fact that the entire series was being replaced; changing the databound property to an ObservableCollection
made no difference.
In the end, we changed our code to include a delay between changes to the underlying data and those changes being reflected in the ViewModel's bound collection property. While it does depend to an extent on the speed of the machine on which the app is running, we've settled on a 0.5sec delay between the last underlying data change and the ViewModel property updating. This prevents the chart being updated more than every 0.5secs and it seems to do the job.
At some point, I'll actually go through the WPFToolkit code and see what I can do to fix it, but for now, this workaround's worth noting.
回答4:
What you are doing ought to work. The fact that it doesn't indicates WPF Toolkit has a bug.
WPF Toolkit implements OnItemsSourceChanged() on DataPointSeries to detect the case where you replace ItemsSource and call Refresh(). Refresh() has code to remove all data points (except ones that are already animating away) and then create a whole new set of DataPoints. Obviously that code has a bug in it. I looked for a minute or two at it but didn't see what was wrong. I would start by upgrading to the latest WPFToolkit release. If that doesn't fix it, you might step through the DataPointSeries.Refresh() method when the ItemsSource is changed to see what is happening there and why it isn't removing the old DataPoint objects.
Or, as you observed, you could work around the bug by just replacing the collection content instead of the collection as a whole.
来源:https://stackoverflow.com/questions/3039141/binding-update-adds-news-series-to-wpf-toolkit-chart-instead-of-replacing-updat