I've been working with XNA for the past few days and I find it amazing how far my project has progressed in that time. One of my favorite creations is a simple scripting system that allows me to register methods and properties that can be called from the in-game console. To better manage the graphics settings (and to clean up the main Game class), I moved most of the GraphicsDevice code into a GraphicsManager component. Then, I registered a few methods from it into the scripting system such as "set_resolution" and such.
Unfortunately, I ran into a little problem. For some reason (still unknown to me), the scripting system (which is a custom Reflection-driven system) wanted to invoke everything on a separate thread. If anyone knows why, please don't hesitate to tell me. Anyway, when I tried to edit a property on the GraphicsDevice, I would get a cross-thread invocation exception. Apparently, changes to the GraphicsDevice can only be made on the game's main thread. Which makes sense, I guess.
Fortunately, changes to the GraphicsDevice are made with one method:
GraphicsDeviceManager.ApplyChanges()
That made things pretty easy to fix.
I created a new property in my GraphicsManager called IsChanged. When I update a property on the GraphicsDevice, I set IsChanged to true instead of calling ApplyChanges(). In my game's Update method, I simply check if GraphicsManager.IsChanged is true and execute GraphicsDeviceManager.ApplyChanges() from there. That way, while the changes are actually made on another thread, they are applied on the main thread.
No more exceptions! Unfortunately, I don't know how well this will work as the whole thing gets more complicated. Thanks to KeeperOfTheSoul on the ##csharp IRC channel (FreeNode), there is another solution. However, it's a bit more complicated, so I decided not to use it just yet.
I could create a Queue of delegates in my GraphicsManager class. When I need to make a change on my main game thread, I add a new delegate to the queue. In the game's Update method, I just pop a delegate off the queue and invoke it. It does basically the same thing as the first method. However, since I can apply changes with a single method, I figured this solution was a little more than what I needed. It certainly sounds like it would work, though. Thanks, KeeperOfTheSoul!