This morning I had some time to play around with powerpoint. Below is a diagram depicting how BruTile's tile fetcher works. The tile fetcher runs on a worker thread and fetches tiles from the web or the disk. The idea behind its setup was that the direct communication between the UI thread and the fetcher thread would be minimized. The only direct communication is a ViewChanged call to the fetcher, telling it the user is panning or zooming and a DataChanged callback telling the UI it should render. The fetcher dumps incoming tiles into the MemoryCache, which is just a big bag of tiles. The UI renderer retrieves whichever tiles it needs.
Both the fetcher and the renderer can use all kinds of smart tricks. The fetcher can pre-fetch tiles based on its current view, or on the way the view changes over time. The renderer could search for alternative tiles (higher or lower levels) when the optimal tiles are not available. Those strategies should be tuned to support each other. For instance, in the current implementation the renderer uses higher level tiles when the optimal tiles are not available, and the fetcher pre-fetches higher level tiles to assist the renderer. But the way they play together is not specified in the interface. This loose coupling keeps things simple and flexible and the renderer never has to wait for the fetcher which results in a smooth (perceived) performance.