Observer pattern is appropriate with some specializaiton. A more specialized version of the observer pattern for this type of scenario is the EventAggregator pattern. The event aggregator pattern is ideal for this type of scenario.
In short the event aggregator allows you to centralize the publishing/subscription of events. Therefore all subscribers and publishers talk only to the EventAggregator. Subscribers subscribe to events and publishers command the event aggregator to publish something.
The event aggregator pattern also decouples each publisher subscriber from each other. This eliminates the need for the child forms to reference the parent forms.
Jeremy Miller provides a good example in his Build Your Own Cab series. Due to my new membership I cant post the links to the sites but just a do a search for the following items.
EventAggregator by Martin Fowler
Build Your Own CAB series by Jeremy Miller (codebetter.com)
EventAggregator in PRISM
Here is a simple example I cooked up using C# and generics. This is by no means complete. It is just to illustrate a simplified example. For a more complete patter turn to Jeremy Millers example.
[code]
//Sample Custom Event args
using System;
namespace EventAggregatorPatternDemo
{
public class CloseAllFormsEventArgs : EventArgs
{
}
}
//Sample Form Code
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace EventAggregatorPatternDemo
{
public partial class GraphForm : Form, IListener
{
public GraphForm()
{
InitializeComponent();
}
private void GraphForm_Load(object sender, EventArgs e)
{
EventAggregator.GetTheEventAggregator().Subscribe<CloseAllFormsEventArgs>(this);
}
public void Handle<TEventArgs>(TEventArgs e)
{
if (e.GetType() == typeof(CloseAllFormsEventArgs))
{
this.Close();
}
}
private void btnCloseAll_Click(object sender, EventArgs e)
{
EventAggregator.GetTheEventAggregator().Publish(this, new CloseAllFormsEventArgs());
}
private void GraphForm_FormClosed(object sender, FormClosedEventArgs e)
{
EventAggregator.GetTheEventAggregator().CancelSubscription<CloseAllFormsEventArgs>(this);
}
}
}
//Event Aggregator code
using System;
using System.Collections.Generic;
namespace EventAggregatorPatternDemo
{
public interface IListener
{
void Handle(TEventArgs e);
}
public class EventAggregator
{
static EventAggregator _TheEventAggregator;
readonly Dictionary<Type, List<IListener>> _listeners;
private EventAggregator()
{
_listeners = new Dictionary<Type, List<IListener>>();
}
public static EventAggregator GetTheEventAggregator()
{
if(_TheEventAggregator == null)
{
_TheEventAggregator = new EventAggregator();
}
return _TheEventAggregator;
}
public void Publish<TEventArgs>(object sender, TEventArgs e)
{
if(_listeners.ContainsKey(e.GetType()))
{
var listOfSubscribers = _listeners[e.GetType()];
for(int i = listOfSubscribers.Count - 1; i > -1; i--)
{
listOfSubscribers[i].Handle(e);
}
}
}
public void Subscribe<TEventArgs>(IListener listener)
{
if(_listeners.ContainsKey(typeof(TEventArgs)))
{
_listeners[typeof(TEventArgs)].Add(listener);
}
else
{
List<IListener> newListenerList = new List<IListener>();
newListenerList.Add(listener);
_listeners.Add(typeof(TEventArgs), newListenerList);
}
}
//Cancels all subscriptions
public void CancelSubscription<TEventArgs>(IListener listener)
{
Type eventArgsType = typeof(TEventArgs);
if (_listeners.ContainsKey(eventArgsType))
{
//Remove from the end
for (int i = _listeners[eventArgsType].Count-1; i > -1; i-- )
{
//If the objects are the same
if(ReferenceEquals(_listeners[eventArgsType][i], listener))
{
_listeners[eventArgsType].RemoveAt(i);
}
}
}
}
}
}
[/code]