Join 136,066 C# Programmers for FREE! Get instant access to thousands of C# experts, tutorials, code snippets, and more! There are 1,599 people online right now. Registration is fast and FREE... Join Now!
Hey guys, I have been looking up some information on the Observer design pattern, but I dont really know if it applies to my application. Most of the examples I see paint it as a way to separate GUI elements from backend classes.
What I am wondering about is how to best keep track of an application's state if it contains two windows. Let me give an example:
I have a program with a main window that can spawn a second, graphing window. The second window can start and stop graphing, but there is also a button on the main window to start and stop graphing.
The issue is, I need to keep both forms on the same state. If I click "Start Graphing" on the main window, it had better start the graphing procedure on the second, and change the button on the second window to reflect that graphing has been initialized (usually by changing the button text to "Stop Graphing").
Communicating between two forms is a common problem. But I don't just want data to be passed from one form to another, I want the state-machine between two forms to be synchronized, if that makes sense.
There is an implicit design pattern in C# that's superior to the Observer in every way. It's the event model and it's a major strength of the language. I've always meant to write a tutorial on this, actually. It's more fun to write code.
Rather that kill myself explaining, here's some code.
Form1.cs
csharp
public partial class Form1 : Form { private Form2 childForm = null; public Form1() { InitializeComponent(); ButtonStateInit(); }
private void ButtonStateInit() { this.bInvoke.Enabled = true; // we have no start and stop when no child form this.bStart.Enabled = false; this.bStop.Enabled = false; }
private void bInvoke_Click(object sender, EventArgs e) { // dont ivoke twice. this.bInvoke.Enabled = false; childForm = new Form2(); // listen to standard close event, for button reset childForm.FormClosed += new FormClosedEventHandler(childForm_FormClosed);
// listen to custom event, for state change childForm.RunningStateChanged += new Form2.RunningStateChangedHandler(childForm_RunningStateChanged);
// show the form childForm.Show(); }
void childForm_FormClosed(object sender, FormClosedEventArgs e) { // closed, but the buttons back ButtonStateInit(); }
void childForm_RunningStateChanged(object sender, EventArgs e) { // not using my object var (childForm) for this, we often don't have one // so this is how it's usually done Form2 frm = (Form2)sender; // look at the form state, update my buttons this.bStop.Enabled = frm.RunningState; this.bStart.Enabled = !this.bStop.Enabled; }
private void bStop_Click(object sender, EventArgs e) { // tell the child, the child with then tell me and I'll update the buttons childForm.RunningState = false; } private void bStart_Click(object sender, EventArgs e) { // tell the child, the child with then tell me and I'll update the buttons childForm.RunningState = true; } }
Form2.cs
csharp
public partial class Form2 : Form { public Form2() { InitializeComponent(); }
// set up an event, we need a delegate public delegate void RunningStateChangedHandler(object sender, EventArgs e); // an the event itself public event RunningStateChangedHandler RunningStateChanged;
// a nice public property, so outside forces can mess with our state public bool RunningState { get { return this.bStop.Enabled; } set { // nothing to do if (this.bStop.Enabled && value) { return; } this.bStop.Enabled = value; this.bStart.Enabled = !this.bStop.Enabled; // do something //... // tell listeners if (this.RunningStateChanged != null) { // we have listeners, fire an event RunningStateChanged(this, new EventArgs()); } } }
There is an implicit design pattern in C# that's superior to the Observer in every way. It's the event model and it's a major strength of the language. I've always meant to write a tutorial on this, actually. It's more fun to write code.
Rather that kill myself explaining, here's some code.
Form1.cs
csharp
public partial class Form1 : Form { private Form2 childForm = null; public Form1() { InitializeComponent(); ButtonStateInit(); }
private void ButtonStateInit() { this.bInvoke.Enabled = true; // we have no start and stop when no child form this.bStart.Enabled = false; this.bStop.Enabled = false; }
private void bInvoke_Click(object sender, EventArgs e) { // dont ivoke twice. this.bInvoke.Enabled = false; childForm = new Form2(); // listen to standard close event, for button reset childForm.FormClosed += new FormClosedEventHandler(childForm_FormClosed);
// listen to custom event, for state change childForm.RunningStateChanged += new Form2.RunningStateChangedHandler(childForm_RunningStateChanged);
// show the form childForm.Show(); }
void childForm_FormClosed(object sender, FormClosedEventArgs e) { // closed, but the buttons back ButtonStateInit(); }
void childForm_RunningStateChanged(object sender, EventArgs e) { // not using my object var (childForm) for this, we often don't have one // so this is how it's usually done Form2 frm = (Form2)sender; // look at the form state, update my buttons this.bStop.Enabled = frm.RunningState; this.bStart.Enabled = !this.bStop.Enabled; }
private void bStop_Click(object sender, EventArgs e) { // tell the child, the child with then tell me and I'll update the buttons childForm.RunningState = false; } private void bStart_Click(object sender, EventArgs e) { // tell the child, the child with then tell me and I'll update the buttons childForm.RunningState = true; } }
Form2.cs
csharp
public partial class Form2 : Form { public Form2() { InitializeComponent(); }
// set up an event, we need a delegate public delegate void RunningStateChangedHandler(object sender, EventArgs e); // an the event itself public event RunningStateChangedHandler RunningStateChanged;
// a nice public property, so outside forces can mess with our state public bool RunningState { get { return this.bStop.Enabled; } set { // nothing to do if (this.bStop.Enabled && value) { return; } this.bStop.Enabled = value; this.bStart.Enabled = !this.bStop.Enabled; // do something //... // tell listeners if (this.RunningStateChanged != null) { // we have listeners, fire an event RunningStateChanged(this, new EventArgs()); } } }
// on load, set a false state private void Form2_Load(object sender, EventArgs e) { this.RunningState = false; } }
I know it's a lot to chew on. I'll get the tutorial done sometime. Until then, hope this helps.
That's a great example. Very straightforward, I think. I am going to hold off for a few days to implement this, but I think that your code really laid the groundwork well. Thanks again.