WPF: Stops PlottableCountTimer on Unload#1117
Conversation
|
Hi @bclehmann , if it remains in this form, then it is worth shortening to 1 line: Unloaded += (s , e) => PlottableCountTimer.Stop(); |
There was a problem hiding this comment.
According to this SO post:
There are several controls that would cause your control to be loaded/unloaded multiple times.
I believe that the PlottableCountTimer should be started on the Loaded event, otherwise the timer will not be restarted after the first unload event:
PlottableCountTimer.Tick += PlottableCountTimer_Tick;
PlottableCountTimer.Interval = new TimeSpan(0, 0, 0, 0, milliseconds: 10);
Loaded += (_, _) => PlottableCountTimer.Start();
Unloaded += (_, _) => PlottableCountTimer.Stop();
|
Great catch @Orace. If we do not allow the user to manually manipulate the Plottable list. We don't really need a timer. We can raise And for this PR, is definitely a good fix. Who would have thought that in WPF controls can be loaded and unloaded multiple times? |
|
I'm not sure that the proposed implementation fix all corner cases for the memory leak. If we remove the parent element (like a grid) from it's parent (like a window) does the The proposed implementation may cause an other issue in my case (where I detected the memory leak too). I use a wpf objects tree to create a XPS report file (later converted to pdf). The wpf tree is never connected to a window and so I'm not even sure that the The implementation should get rid of the |
|
Hi @bclehmann, @StendProg, and @Orace 👋 I've been busy traveling and working on some personal projects but I anticipate having more time to work on ScottPlot again. Intended Behavior (and why I used a timer)To get us all on the same page, the core problem this timer thing is trying to achieve is:
I'm not using a
When should the timer be started?
This makes sense. This PR could be modified to achieve this. Similar functionality may need to be added to the WinForms and Avalonia controls. Alternative Solution (use the render queue?)Maybe instead of using a timer in the control to trigger plottable count checks and renders, a change to the plottables list could fire an event that adds add a fast delayed render (10 ms) to the queue. @StendProg you may be the most experienced with this system, what do you think of this idea? |
|
I think if we were to ever consider automatically updating when the user changes plot properties or data then the render queue would be the most extensible solution that's been brought up. However, you could also have a system where these updates invoke a render more directly, which would probably make removing unnecessary renders easier. I'm thinking of a simple debouncer, where it executes some time after the last time it was invoked. A smart delay is probably ~16ms so it's only 1 frame. I don't think we'd need to manually flush as I'd be very impressed if someone managed to continuously lock up this function for even one frame. In principle, you could have both, when a proactive render is pushed to the render queue it doesn't render directly but simply calls a debounced render method. This should simplify things as we don't have to manage two different queue-like things, they can be treated exactly the same save for the handler at the other end of the queue. |
|
For what it's worth, I still maintain that the inconsistency introduced by having some updates be automatically rendered but not others serves to confuse the API. One still ought to call And in my opinion, having it update on timer instead of using an observable collection will normally mean that adjusting properties will be reflected in the automatic render. But it also introduces a race condition where the render happens after adding the plottable but before adjusting the properties. While adjusting virtually all properties should be very fast and this bad path should be very rare, it's an unnecessary bug which is obscenely difficult to even reproduce. And it's not unforeseeable that we have more complicated properties that can be slower to update, such as if we were to have properties that caused heatmaps to be renormalized. Such a thing would make racing the two codepaths much more likely. |
Implementation Using the Render Queue
I think something similar is in place, and this could be extended to provide the 16ms functionality you recommend. EventsProcessor.cs has a "delayed render timer" and when it crosses a threshold a render is performed. Requests reset the timer so two requests in a row will just reset the timer twice and result in a single render. Right now the threshold is a fixed number ( Should Automatic
|
|
NPM packages often give warnings or deprecation notices in the console? We could detect if they didn't call render and then log? It's not particularly visible, but one could go further and draw text on the plottable or even throw if |
This is an interesting idea! I think I prefer this option over console debug messages and pop-up readmes 🤔 I don't want to make this decision quickly (it would be a breaking change), but I'm liking the idea of removing the complex/confusing automatic render system, and this API change and warning message may be the lesser of two evils. |
This PR is an improvement so I'll merge it now. Thank you everyone for your input! Eventually I will remove this timer completely and mandate that the user call |

New Contributors:
please review CONTRIBUTING.md
Purpose:
#1115