An element of IssueVision that I've taken for my Smart Client application is the Observer pattern. If you Google IObserver you'll find some good articles, but they're usually way too complicated. Hopefully this post helps simplify the Observer pattern for those interested in it. This is also covered in the DevDays 2004 Smart Track presentation #1 and of course in the IV source.
The Observer pattern is how you coordinate multiple UI views of the same set of data. You have a SUBJECT, which is the common set of core data we're interested in. For IssueVision the subject is all about staff, issues, issue history and issue details.
With the IssueVision UI as a guide (shown at bottom), there are multiple panes that care about the subject and need to know when the subject changes or is modified. The panes need to be able to tell the subject when they need to change the current record, change the display of a record count, a statusbar messages, etc.
We use the observer pattern to wire up the various observers of the subject data. All observer changes in focus or selection or whatever, pass through the subject. Then when a subject detects a change that the different panes may care about, it sends out an event.
Let's take the Synchronization_Finished action, for instance. In the IssueSubject.cs we create our delegate, the event, and fire it when any synchronization process completes. Here's what that looks like.
public delegate void Synchronization_FinishedEventHandler(object sender, EventArgs e);
public virtual event Synchronization_FinishedEventHandler Synchronization_Finished;
// Then, when a synchronization is completed in IssueSubject.cs it fires the event.
Synchronization_Finished(this, EventArgs.Empty);
// Which goes out to the observers, like the MainForm, for instance which executes its Synchronization_Finished event method.
private void IssueSubject_Synchronization_Finished(object sender, System.EventArgs e)
{
UpdateOnlineStatus();
}
Then in the Main Form, we create an instance of the Subject and each pane's subject--each pane has a member variable called subject which is simply a reference to the subject. They all have a pointer to it in other words. (Keep in mind that while IV provides a fully working Observer pattern, it's UI is rather simplistic with all usercontrols residing pretty much on the mainform. This would not be the case in the Real World.) Here's what the Main Form reference and initialization looks like.
m_issueSubject = new IssueSubject(this.components);
paneStaff.Subject = m_issueSubject;
paneMiddle.Subject = m_issueSubject;
// etc...
m_issueSubject.Synchronization_Finished += new IssueSubject.Synchronization_FinishedEventHandler(IssueSubject_Synchronization_Finished);
// etc...
m_issueSubject.Initialize();
So now, whenever the observers change the state of the subject, all other observers are affected. An example in IssueVision would be clicking on a staffer in the staff tree view resulting in the issue pane displaying issues applying only to that staff member.
There's a lot of intricate coordination going on, but what's nice is that you can build these panes independently of each other and the only thing you have to worry about are the events coming back from the subject.
So there ya go. The Observer Pattern.