@@ -57,6 +57,11 @@ public abstract partial class PlotBase : TemplatedControl, IPlotView
5757 /// </summary>
5858 private Panel panel ;
5959
60+ /// <summary>
61+ /// Invalidation flag (0: no update, 1: update, 2: update date).
62+ /// </summary>
63+ private int isUpdateRequired ;
64+
6065 /// <summary>
6166 /// Invalidation flag (0: no update, 1: update visual elements).
6267 /// </summary>
@@ -224,21 +229,22 @@ public void ResetAllAxes()
224229 /// <param name="updateData">The update Data.</param>
225230 public void InvalidatePlot ( bool updateData = true )
226231 {
227- if ( Width <= 0 || Height <= 0 )
228- {
229- return ;
230- }
232+ // perform update on UI thread
233+ var updateState = updateData ? 2 : 1 ;
234+ int currentState = isUpdateRequired ;
231235
232- // TODO: legend on/off crash (issue with Legend hit-test implementation, really)
233- UpdateModel ( updateData ) ;
234-
235- if ( Interlocked . CompareExchange ( ref isPlotInvalidated , 1 , 0 ) == 0 )
236+ while ( currentState < updateState )
236237 {
237- // Invalidate the arrange state for the element.
238- // After the invalidation, the element will have its layout updated,
239- // which will occur asynchronously unless subsequently forced by UpdateLayout.
240- BeginInvoke ( InvalidateArrange ) ;
241- BeginInvoke ( InvalidateVisual ) ;
238+ if ( Interlocked . CompareExchange ( ref isUpdateRequired , updateState , currentState ) == currentState )
239+ {
240+ isUpdateRequired = updateState ;
241+ BeginInvoke ( ( ) => UpdateModel ( updateData ) ) ;
242+ break ;
243+ }
244+ else
245+ {
246+ currentState = isUpdateRequired ;
247+ }
242248 }
243249 }
244250
@@ -386,10 +392,30 @@ protected override Size ArrangeOverride(Size finalSize)
386392 /// <param name="updateData">The update Data.</param>
387393 protected void UpdateModel ( bool updateData = true )
388394 {
389- if ( ActualModel != null )
395+ if ( Width <= 0 || Height <= 0 || ActualModel == null )
396+ {
397+ return ;
398+ }
399+
400+ lock ( this . ActualModel . SyncRoot )
390401 {
391- ( ( IPlotModel ) ActualModel ) . Update ( updateData ) ;
402+ var updateState = ( Interlocked . Exchange ( ref isUpdateRequired , 0 ) ) ;
403+
404+ if ( updateState > 0 )
405+ {
406+ ( ( IPlotModel ) ActualModel ) . Update ( updateState == 2 ) ;
407+ }
408+ }
409+
410+ if ( Interlocked . CompareExchange ( ref isPlotInvalidated , 1 , 0 ) == 0 )
411+ {
412+ // Invalidate the arrange state for the element.
413+ // After the invalidation, the element will have its layout updated,
414+ // which will occur asynchronously unless subsequently forced by UpdateLayout.
415+ BeginInvoke ( InvalidateArrange ) ;
416+ BeginInvoke ( InvalidateVisual ) ;
392417 }
418+
393419 }
394420
395421 /// <summary>
@@ -482,26 +508,36 @@ private void UpdateVisuals()
482508
483509 if ( ActualModel != null )
484510 {
485- if ( DisconnectCanvasWhileUpdating )
511+ lock ( this . ActualModel . SyncRoot )
486512 {
487- // TODO: profile... not sure if this makes any difference
488- var idx = panel . Children . IndexOf ( canvas ) ;
489- if ( idx != - 1 )
513+ var updateState = ( Interlocked . Exchange ( ref isUpdateRequired , 0 ) ) ;
514+
515+ if ( updateState > 0 )
490516 {
491- panel . Children . RemoveAt ( idx ) ;
517+ ( ( IPlotModel ) ActualModel ) . Update ( updateState == 2 ) ;
492518 }
493519
494- ( ( IPlotModel ) ActualModel ) . Render ( renderContext , new OxyRect ( 0 , 0 , canvas . Bounds . Width , canvas . Bounds . Height ) ) ;
495-
496- // reinsert the canvas again
497- if ( idx != - 1 )
520+ if ( DisconnectCanvasWhileUpdating )
498521 {
499- panel . Children . Insert ( idx , canvas ) ;
522+ // TODO: profile... not sure if this makes any difference
523+ var idx = panel . Children . IndexOf ( canvas ) ;
524+ if ( idx != - 1 )
525+ {
526+ panel . Children . RemoveAt ( idx ) ;
527+ }
528+
529+ ( ( IPlotModel ) ActualModel ) . Render ( renderContext , new OxyRect ( 0 , 0 , canvas . Bounds . Width , canvas . Bounds . Height ) ) ;
530+
531+ // reinsert the canvas again
532+ if ( idx != - 1 )
533+ {
534+ panel . Children . Insert ( idx , canvas ) ;
535+ }
536+ }
537+ else
538+ {
539+ ( ( IPlotModel ) ActualModel ) . Render ( renderContext , new OxyRect ( 0 , 0 , canvas . Bounds . Width , canvas . Bounds . Height ) ) ;
500540 }
501- }
502- else
503- {
504- ( ( IPlotModel ) ActualModel ) . Render ( renderContext , new OxyRect ( 0 , 0 , canvas . Bounds . Width , canvas . Bounds . Height ) ) ;
505541 }
506542 }
507543 }
@@ -514,11 +550,11 @@ private static void BeginInvoke(Action action)
514550 {
515551 if ( Dispatcher . UIThread . CheckAccess ( ) )
516552 {
517- Dispatcher . UIThread . InvokeAsync ( action , DispatcherPriority . Loaded ) ;
553+ action ? . Invoke ( ) ;
518554 }
519555 else
520556 {
521- action ? . Invoke ( ) ;
557+ Dispatcher . UIThread . InvokeAsync ( action , DispatcherPriority . Loaded ) ;
522558 }
523559 }
524560 }
0 commit comments