How to "share" information between user controls?
I'm making a map editor for a 2D platform game, which involves having a custom control to display a list of possible tile types and another custom control to render a grid of the tiles. I have both controls already made and working, but I really don't like the way they interact.
The grid control needs to know which tile type is currently selected so that it could make new tiles of that type when the user clicks a tile. It also needs to associate an actual image with a tile type so that it could draw the tile grid.
The tileset control stores two synchronized lists, one with tile types and another with pictureboxes that display an image of each tile type. I don't have a dictionary for this since sometimes I need just the tile types and sometimes just the pictureboxes.
The way I have it set up right now is with events. The tile set control fires an event every time the selection is changed., and another one when the tileset changes (when a user adds another tile type). The main form registers for those events and updates each existing level on the current selection, or the new tileset.
The way I solve this problem is with events. So for every variable between classes that needs updating, I have an event that fires off when it changes in tileset control. This is pretty tedious.
I also plan to add a tool menu that will have sliders/buttons/checkboxes etc. that will need to update parameters of the level grid control. I REALLY don't plan on using events for this, especially when I will have several controls and will probably add more parameters later on.
So, is there an easier way to solve this?
I'd probably use the mediator pattern for this kind of thing. The various controls would register message handlers with the mediator class, one for each type of message they are interested in. Each can also send messages to the mediator when interesting events happen. When the mediator receives a message, it broadcasts it to all registered listeners for that type of message. So, for your case, each instance of the grid control would register with the mediator to receive "TileSelectionChanged" and "TileSetChanged" messages, and the tile set control would use the mediator to broadcast messages when these events occur, passing the relevant data along with the message. In the future, when you implement your tool menu, all you need to do is send a message to the mediator for each menu action, and register a handler for each of the message types in any controls which need to respond to them.
This pattern is, in a way, similar to what you're already doing: the main form is acting as a kind of mediator, listening to events in one control and broadcasting it to other controls which need to be updated. It's not the same, though. The key difference is that unlike a true mediator, your main form is responsible for actively registering for all of the events, which is where maintenance tediousness is introduced. A true mediator is more passive, letting the classes which want to publish messages do so, and routing the messages to any interested listeners. It neither knows nor cares where the message comes from or what it means, it just passes it along. In your current implementation, you have three places that need to change when a new event type is conceived: the originating control, the main form, and the control that ultimately responds to the event. With the mediator pattern, the change is reduced to two locations: the originating control and the responding control.