在 WPF 中使用数据绑定时,OxyPlot 不刷新
Posted
技术标签:
【中文标题】在 WPF 中使用数据绑定时,OxyPlot 不刷新【英文标题】:OxyPlot not refreshing when using data binding in WPF 【发布时间】:2014-06-25 21:34:56 【问题描述】:我正在异步获取数据并尝试通过 LineSeries 填充绘图,但更新绑定集合 (ObservableCollection) 时绘图不会刷新。注意:当绑定集合更改时,我有一个 XAML 行为来调用 InvalidatePlot(true)。
谁能解释为什么剧情没有按预期更新?
WPF .Net 4.0 OxyPlot 2014.1.293.1
我有以下 XAML 数据模板,您可以看到 LineSeries ItemsSource 绑定到 ViewModel 中的属性 (PlotData):
<DataTemplate DataType="x:Type md:DataViewModel">
<Grid>
<oxy:Plot x:Name="MarketDatePlot"
Margin="10">
<oxy:Plot.Axes>
<oxy:DateTimeAxis Position="Bottom"
StringFormat="dd/MM/yy"
MajorGridlineStyle="Solid"
MinorGridlineStyle="Dot"
IntervalType="Days"
IntervalLength="80" />
<oxy:LinearAxis Position="Left"
MajorGridlineStyle="Solid"
MinorGridlineStyle="Dot"
IntervalLength="100" />
</oxy:Plot.Axes>
<oxy:LineSeries ItemsSource="Binding Path=PlotData, Mode=OneWay" />
<i:Interaction.Behaviors>
<behaviors:OxyPlotBehavior ItemsSource="Binding Path=PlotData, Mode=OneWay" />
</i:Interaction.Behaviors>
</oxy:Plot>
</Grid>
</DataTemplate>
正如我所说,ViewModel 异步请求并填充绑定集合(绑定集合的实际填充发生在 UI 线程上):
public sealed class DataViewModel : BaseViewModel, IDataViewModel
private readonly CompositeDisposable _disposable;
private readonly CancellationTokenSource _cancellationTokenSource;
private readonly RangeObservableCollection<DataPoint> _plotData;
public DataViewModel(DateTime fromDate, DateTime toDate, IMarketDataService marketDataService, ISchedulerService schedulerService)
_plotData = new RangeObservableCollection<DataPoint>();
_disposable = new CompositeDisposable();
if (fromDate == toDate)
// nothing to do...
return;
_cancellationTokenSource = new CancellationTokenSource();
_disposable.Add(Disposable.Create(() =>
if (!_cancellationTokenSource.IsCancellationRequested)
_cancellationTokenSource.Cancel();
));
marketDataService.GetDataAsync(fromDate, toDate)
.ContinueWith(t =>
if (t.IsFaulted)
throw new Exception("Failed to get market data!", TaskHelper.GetFirstException(t));
return t.Result.Select(x => new DataPoint(DateTimeAxis.ToDouble(x.Time), x.Value));
, schedulerService.Task.Default)
.SafeContinueWith(t => _plotData.AddRange(t.Result), schedulerService.Task.CurrentSynchronizationContext);
public void Dispose()
_disposable.Dispose();
public IEnumerable<DataPoint> PlotData
get return _plotData;
XAML 行为如下所示:
(我似乎无法再粘贴代码了,所以保存时总是抛出错误)
【问题讨论】:
什么是RangeObservableCollection
?此外,如果您的财产实际上是 ObservableCollection
而不是 IEnumerable<>
,这有什么区别吗?我知道底层数据成员是(假设 RangeObservableCollection
派生自 ObservableCollection
),但我不确定这对于绑定系统是否足够好。
它确实来自 ObservableCollection,我将其更改为 ObservableCollection,但它仍然不刷新
我知道BackgroundWorker支持结果的上报,_disposable有这个功能吗?
OxyPlot 对象的所有更新都在 UI 线程上完成
如果我很粗鲁,请原谅我,但你有没有看过这个example。您应该再次检查您的代码并将相互的东西与示例进行比较,我相信您很快就会找到它。
【参考方案1】:
添加数据时,OxyPlot 不会自动更新。
你必须调用 plotname.InvalidatePlot(true);
并且它必须在 UI 调度线程上运行,即
Dispatcher.InvokeAsync(() =>
plotname.InvalidatePlot(true);
【讨论】:
【参考方案2】:不知道人们是否还需要这个,但我在 itemsource 不更新图表时遇到了同样的问题。现有的解决方案都没有帮助我。
嗯,我终于找到了整个事情不起作用的原因。在我实际初始化它之前,我已经将我的集合分配给了 itemsource(新的 Observable....)。
当我尝试将已经初始化的集合分配给我的 itemsource 时,整个事情开始工作了。
希望这对某人有所帮助。
【讨论】:
我也一样。InvalidatePlot(true)
到处都是,将 ObservableCollection 的计数放在 TextBox 旁边......这可能很容易,就像 Ales 只需将 SampleValues = new ObservableCollection<Reading>();
移动到 InitializeComponent();
上方一样
【参考方案3】:
我知道这是一个老问题,但经过数小时的仔细检查后,也许有人会使用我的答案。我使用 MVVM。 我正在使用 await Task.Run(()=> update()); 更新数据这并没有在我的 UI 中呈现我的情节。在设置它之前,我也在初始化我的 PlotModel。 事实证明,在该 update() 方法中初始化 PlotModel 并没有在我的 UI 中注册。在调用该任务运行之前,我必须对其进行初始化。
public ViewModel()
Plot = new PlotModel(); //(Plot is a property using
// INotifyPropertyChanged)
PlotGraph = new RelayCommand(OnPlotGraph);
public RelayCommand PlotGraph get; set;
private async void OnPlotGraph()
await Task.Run(() => Update());
private void Update()
var tempPlot = new PlotModel();
//(set up tempPlot, add data to tempPlot)
Plot = tempPlot;
【讨论】:
以上是关于在 WPF 中使用数据绑定时,OxyPlot 不刷新的主要内容,如果未能解决你的问题,请参考以下文章
InvalidatePlot 上 WPF 中大数据的 OxyPlot 性能问题