Fix for calls to ImageRenderer::OnTimer (Invoke or BeginInvoke cannot be...
ObjectListView - ListView on caffeine, guarana and steroids
Brought to you by:
grammarian
Hi,
with been encountering repeated exceptions like "Invoke or BeginInvoke cannot be called on a control until the window handle has been..." with ObjectListView and ImageRenderer's async events (OnTimer) in an ImageListView that was used in a conditional dialog - and whose Win32 handle was therefore not yet created or already disposed. A sample stack would look like this (pasted to help others searching for it)
at System.Windows.Forms.Control.WaitForWaitHandle(WaitHandle waitHandle) at System.Windows.Forms.Control.MarshaledInvoke(Control caller, Delegate method, Object[] args, Boolean synchronous) at System.Windows.Forms.Control.Invoke(Delegate method, Object[] args) at System.Windows.Forms.Control.Invoke(Delegate method) at BrightIdeasSoftware.ImageRenderer.OnTimer(Object state) at System.Threading._TimerCallback.TimerCallback_Context(Object state) at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx) at System.Threading._TimerCallback.PerformTimerCallback(Object state)
We patched ObjectListView as follows:
Index: Renderers.cs =================================================================== --- Renderers.cs (revision 762) +++ Renderers.cs (working copy) @@ -2379,6 +2379,12 @@ if (this.ListView == null || this.Paused) return; + if (this.ListView.Disposing || this.ListView.IsDisposed) + return; + + if (!this.ListView.IsHandleCreated) + return; + if (this.ListView.InvokeRequired) this.ListView.Invoke((MethodInvoker)delegate { this.OnTimer(state); }); else
Maybe you can merge this into trunk tree?
Regards,
Sören
here the diff against trunk:
Thank you for this fix.
I will implement a similar fix for the next release.
Hi Phillip,
I'm still getting some crashes for the same problem, but not as often as before (still the object is disposed when Invoke is called).
Perhaps the code needs a private object like disposeLock and some lock(disposeLock) {...} sections, as the timer might always trigger un-synchronized to the disposing.
So - pretty sure my suggestion is not yet complete.
btw: I prevented my code from crashing by just calling Pause() on the ImageRenderer, as I'm only showing .png anyway..
Sören