I just ran across an article by Justin Rogers explaining Control.Invoke, BeginInvoke/EndInvoke, and InvokeRequired in depth.
This is not light reading. But there are some interesting consequences to the way these things are implemented, that I wouldn’t have expected. (E.g., Invoke doesn’t just invoke a single delegate, even if you call it from the UI thread: it actually adds your delegate to the queue, and then processes the entire queue.)