Apply Button

All dialog buttons discussed so far set the dialog box's DialogResult property to a value, which not only has the effect of returning that value to the parent form, but also of closing the dialog box. Sometimes you'll want the parent form to process the changes made in the dialog box while leaving the dialog box open. Many programs implement an Apply button for this purpose.

An Apply button typically is disabled, i.e., grayed out, when the dialog first opens. As soon as any change is made in one of the dialog controls, the button is enabled. Clicking the Apply button makes available to the parent form all the changes made in the dialog box, but leaves the dialog box open. The Apply button is then disabled until the next change in the dialog box is made.

You might be tempted to implement the Apply button by creating a public method in the parent Form class that performs whatever work needs to be done when the Apply button is clicked. The Apply button would simply execute that public method when it was clicked, passing any required information as arguments.

This is not a clean way to implement an Apply button, however, because the dialog box class needs to know too much about the parent class. Also, if other classes invoke your dialog box, the dialog box must know their methods as well. This design tightly couples the dialog class to the forms that invoke it, which is generally an indication of poor design.

A preferable design, which decouples the dialog class from the calling class, is to have the Dialog Box raise an event when the Apply button is clicked. The Apply event would be handled by the parent form and any other interested classes. With this event-driven design, the Dialog box and the parent class can be modified independently of one another; they are associated only through the indirection of publishing and subscribing to the Apply event.

The following example demonstrates how to raise and handle an Apply event when the user clicks the Apply button.

Open Visual Studio .NET and create a new Windows Application project called DialogapplyEvent in the language of your choice. Drag a Button control onto the form. Name the button btnCreate and change the Text property to Create Dialog Box. Resize it as necessary to make it look good. Drag a Label control onto the form and name it lblReturn. Blank out its Text property.

This example creates the dialog box form entirely in code, as opposed to the example shown in Figure 6-1, where the dialog form was created in Visual Studio .NET as part of the project.

Right-click anywhere on the form in the Design window and select View Code. This will open the source code for the Form class. Add the code to create the dialog box class, DialogDemo, shown in Example 6-5 (in C#) or in Example 6-6 (in VB.NET), somewhere inside the Form1 class.

Example 6-5. DialogDemo class using an event in C#

figs/csharpicon.gif

// Dialog box class 
private class DialogDemo : Form
{
 private Button btnApply;
 private TextBox txt;
 public event EventHandler ClickApply;
 
 public DialogDemo( )
 {
 Text = "Apply Dialog Demo";
 FormBorderStyle = FormBorderStyle.FixedDialog;
 BackColor = System.Drawing.Color.Aquamarine;
 ControlBox = false;
 MaximizeBox = false;
 MinimizeBox = false;
 ShowInTaskbar = false;
 Size = new Size(400,200);
 StartPosition = FormStartPosition.CenterScreen;
 
 // Create the OK button
 Button btnOK = new Button( );
 btnOK.Text = "OK";
 btnOK.DialogResult = DialogResult.OK;
 btnOK.Location = new Point(50,50);
 btnOK.TabIndex = 0;
 btnOK.Click += new EventHandler(applyButtonOnClick);
 Controls.Add(btnOK);
 
 // Create the Apply button
 btnApply = new Button( );
 btnApply.Text = "Apply";
 btnApply.Location = new Point(150,50);
 btnApply.TabIndex = 1;
 btnApply.Enabled = false;
 btnApply.Click += new EventHandler(applyButtonOnClick);
 Controls.Add(btnApply);
 
 // Create the Cancel button
 Button btnCancel = new Button( );
 btnCancel.Text = "Cancel";
 btnCancel.DialogResult = DialogResult.Cancel;
 btnCancel.Location = new Point(250,50);
 btnCancel.TabIndex = 2;
 Controls.Add(btnCancel);
 
 // create input text box
 txt = new TextBox( );
 txt.Size = new Size(100,15);
 txt.Location = new Point(150,15);
 txt.TextChanged += new EventHandler(TextBoxChanged);
 Controls.Add(txt);
 
 } // close DialogDemo constructor
 
 private void TextBoxChanged(object sender, EventArgs e)
 {
 TextBox txt = (TextBox)sender;
 DialogDemo dlg = (DialogDemo)txt.Parent;
 dlg.EnableapplyButton = true; 
 }
 
 public bool EnableapplyButton
 {
 get {return btnApply.Enabled; }
 set {btnApply.Enabled = value; }
 }
 
 public string TextOut
 {
 get {return txt.Text; }
 }
 
 private void applyButtonOnClick (object sender, EventArgs e)
 {
 if (ClickApply != null)
 ClickApply(this, new EventArgs( ));
 }
} // close for DialogDemo class

Example 6-6. DialogDemo class using an event in VB.NET

figs/vbicon.gif

' Dialog box class 
private class DialogDemo
 inherits Form
 dim btnApply as Button
 dim txt as TextBox
 public event ClickApply as EventHandler
 
 public sub new ( )
 myBase.New
 Text = "Apply Dialog Demo"
 FormBorderStyle = FormBorderStyle.FixedDialog
 BackColor = System.Drawing.Color.Aquamarine
 ControlBox = false
 MaximizeBox = false
 MinimizeBox = false
 ShowInTaskbar = false
 Size = new Size(400,200)
 StartPosition = FormStartPosition.CenterScreen
 
 ' Create the OK button
 dim btnOK as New Button
 btnOK.Text = "OK"
 btnOK.DialogResult = DialogResult.OK
 btnOK.Location = new Point(50,50)
 btnOK.TabIndex = 0
 AddHandler btnOK.Click, AddressOf applyButtonOnClick
 Controls.Add(btnOK)
 
 ' Create the Apply button
 btnApply = new Button( )
 btnApply.Text = "Apply"
 btnApply.Location = new Point(150,50)
 btnApply.TabIndex = 1
 btnApply.Enabled = false
 AddHandler btnApply.Click, AddressOf applyButtonOnClick
 Controls.Add(btnApply)
 
 ' Create the Cancel button
 dim btnCancel as new Button( )
 btnCancel.Text = "Cancel"
 btnCancel.DialogResult = DialogResult.Cancel
 btnCancel.Location = new Point(250,50)
 btnCancel.TabIndex = 2
 Controls.Add(btnCancel)
 
 ' create input text box
 txt = new TextBox( )
 txt.Size = new Size(100,15)
 txt.Location = new Point(150,15)
 AddHandler txt.TextChanged, AddressOf TextBoxChanged
 Controls.Add(txt)
 
 end sub ' close DialogDemo constructor
 
 private sub applyButtonOnClick(sender as Object, e as EventArgs)
 RaiseEvent ClickApply(me, new EventArgs( ))
 end sub
 
 private sub TextBoxChanged(sender as Object, e as EventArgs)
 dim txt as TextBox = CType(sender,TextBox)
 dim dlg as DialogDemo = CType(txt.Parent,DialogDemo)
 dlg.EnableapplyButton = true 
 end sub
 
 public property EnableapplyButton as Boolean
 get 
 return btnApply.Enabled
 end get
 set
 btnApply.Enabled = value 
 end set
 end property
 
 public ReadOnly property TextOut as string
 get
 return txt.Text 
 end get
 end property
 
end class ' close DialogDemo class

The first thing to note about the DialogDemo class is that it is nested inside the class of the parent form. This design implicitly makes the dialog box available to the Form1 class, but not to any other form. If you want to create a dialog box that will be accessible to different parent forms, then it needs public exposure, probably in a class by itself, or perhaps in a class that also contains other dialog box classes used by your application.

The next thing to note about the DialogDemo class is that it inherits from the Form class. The dialog box being created is just a form, like any other form. What makes it modal is the way it is called from the parent form. When the btnCreate button is clicked, the btnCreate_Click event handler method, shown in C# in Example 6-7 and in VB.NET in Example 6-8, is fired. The ShowDialog( ) method displays the form modally. If the Show( ) method of the Form class were used to display the dialog box rather than ShowDialog( ), it would be a modeless dialog.

Create the event handler for the Click event for the btnCreate button by going to the Design view and double-clicking on the button. Add the code highlighted in Example 6-7 (in C#) or in Example 6-8 (in VB.NET) to the code skeleton for the btnCreate Click event-handler method.

Example 6-7. btnCreate event handler using the ClickApply event in C#

figs/csharpicon.gif

private void btnCreate_Click(object sender, System.EventArgs e)
{
 DialogDemo dlg = new DialogDemo( );
 dlg.EnableapplyButton = false;
 
 // Add the event handler
 dlg.ClickApply += new EventHandler(DialogDemoOnApply);
 
 // Show the dialog modally
 dlg.ShowDialog( );
 
 if (dlg.DialogResult = = DialogResult.OK)
 {lblReturn.Text = dlg.TextOut;}
 else
 {lblReturn.Text = dlg.DialogResult.ToString( );}
}

Example 6-8. btnCreate event handler using the ClickApply event in VB.NET

figs/vbicon.gif

Private Sub btnCreate_Click(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) _
 Handles btnCreate.Click
 dim dlg as new DialogDemo( ) 
 dlg.EnableapplyButton = false
 
 ' Add the event handler
 AddHandler dlg.ClickApply, AddressOf DialogDemoOnApply
 
 ' Show the dialog modally
 dlg.ShowDialog( )
 
 if dlg.DialogResult = DialogResult.OK then
 lblReturn.Text = dlg.TextOut
 else
 lblReturn.Text = dlg.DialogResult.ToString( )
 end if
End Sub

Before the ShowDialog( ) method can be called, the dialog box must be created. The first line of code in the btnCreate_Click method instantiates a new object of type DialogDemo. The instantiation of the dialog box looks like the following:

figs/csharpicon.gif

DialogDemo dlg = new DialogDemo( );

figs/vbicon.gif

dim dlg as new DialogDemo( )

Once the dialog box is instantiated, the EnableapplyButton property is set to false, which disables the Apply button. It will be kept disabled until one of the controls in the dialog box is modified, making the Apply button relevant.

The EnableapplyButton property is of type Boolean. It gets and sets the value of the Enabled property of the Apply button. If the Enabled property of a control is false, then the control is visible, but grayed out, and cannot receive focus. Thus, it cannot be clicked on or otherwise manipulated.

After the dialog box returns from the modal display, the DialogResult property is tested. If the DialogResult is OK, indicating that the dialog box was dismissed with the OK button, then the display label, lblReturn, is populated with the value of the read-only TextOut property of DialogDemo. If the DialogResult value is anything other than OK, which in this example can only be Cancel, then the DialogResult itself is displayed in lblReturn. Depending on the requirements of the application, any of a number of techniques can be used to test the DialogResult return value and process the dialog box control values accordingly.

The DialogDemo class shown in C# in Example 6-5 and in VB.NET in Example 6-6 declares two member variables:

figs/csharpicon.gif

private Button btnApply;
private TextBox txt;

figs/vbicon.gif

dim btnApply as Button
dim txt as TextBox

These are member variables, so they are visible to all the methods and properties in the DialogDemo class.

The DialogDemo constructor sets various properties of the dialog box, including FormBorderStyle, BackColor, ControlBox, and MaximizeBox.

The constructor then instantiates and specifies several controls on the dialog box: OK, Apply, Cancel, and a TextBox for accepting typed user input. Each control is added to the Controls collection of the dialog box.

Both OK and Apply have the same event handler, ApplyButtonOnClick, added to the delegate for their Click event. This is because both buttons cause the text entered into the TextBox control to be displayed on the parent form.

The TextBox control raises the TextChanged event whenever the content of the TextBox is changed, either by adding or deleting characters. The event is handled by the TextBoxChanged event handler method. In C#, the event handler is added to the delegate with this line of code:

figs/csharpicon.gif

txt.TextChanged += new EventHandler(TextBoxChanged);

and the TextBoxChanged method looks like:

figs/csharpicon.gif

private void TextBoxChanged(object sender, EventArgs e)
{
 this.EnableapplyButton = true; 
}

In VB.NET, the event handler is added to the delegate with this line of code:

figs/vbicon.gif

AddHandler txt.TextChanged, AddressOf TextBoxChanged

and the TextBoxChanged method looks like:

figs/vbicon.gif

private sub TextBoxChanged(sender as Object, e as EventArgs)
 me.EnableapplyButton = true 
end sub

An event called ClickApply was declared in the DialogDemo class (Example 6-5 in C#; Example 6-6 in VB.NET). This event will be handled by a method called DialogDemoOnApply, shown in Example 6-9 (in C#) or in Example 6-10 (in VB.NET). Enter the code for DialogDemoOnApply somewhere within the Form1 class, but not within the DialogDemo class.

Example 6-9. DialogDemoOnApply method in C#

figs/csharpicon.gif

private void DialogDemoOnApply(object sender, System.EventArgs e)
{
 DialogDemo dlg = (DialogDemo)sender;
 lblReturn.Text = dlg.TextOut;
 dlg.EnableapplyButton = false; 
}

Example 6-10. DialogDemoOnApply method in VB.NET

figs/vbicon.gif

private sub DialogDemoOnApply(ByVal sender As System.Object, _
 ByVal e As System.EventArgs) 
 dim dlg as DialogDemo = CType(sender, DialogDemo)
 lblReturn.Text = dlg.TextOut
 dlg.EnableapplyButton = false
end sub

The Apply button ultimately raises the ClickApply event when it is clicked. It does so through a multistep process. The Apply button Click event has an event handler method called ApplyButtonOnClick added to its delegate. This is done with the following line of code:

figs/csharpicon.gif

btnApply.Click += new EventHandler(applyButtonOnClick);

figs/vbicon.gif

AddHandler btnApply.Click, AddressOf applyButtonOnClick

The ApplyButtonOnClick method raises the ClickApply method. This method is reproduced here:

figs/csharpicon.gif

private void applyButtonOnClick (object sender, EventArgs e)
{
 if (ClickApply != null)
 ClickApply(this, new EventArgs( ));
}

figs/vbicon.gif

private sub applyButtonOnClick(sender as Object, e as EventArgs)
 RaiseEvent ClickApply(me, new EventArgs( ))
end sub

Since both the OK and Apply buttons perform the same task, with the only difference being that the dialog box closes when the OK button is clicked, they both use the same applyButtonOnClick method as their Click event handler.

VB.NET and C# differ slightly in raising events. In the C# version, you first test to see if any methods have been registered with the delegate before raising the event. If the ClickApply event has not had any event handlers added, its delegate will be null. Since the btnCreate_Click method added DialogDemoOnApply to the ClickApply delegate, the ClickApply delegate is not null, so the ClickApply event is raised. In the VB.NET version, on the other hand, the compiler does the checking for you. If no methods were added to the delegate, nothing happens; otherwise the event is raised. The resulting intermediate language created by the compiler for these two different language implementations are essentially the same.

The parent form handles this ClickApply event by adding an event-handler method, DialogDemoOnApply, to the ClickApply delegate. This was done in the Click event handler for btnCreate, btnCreate_Click, which was listed in Example 6-7 (in C#) and Example 6-8 (in VB.NET). The method was added to the delegate with the following line of code:

figs/csharpicon.gif

dlg.ClickApply += new EventHandler(DialogDemoOnApply);

figs/vbicon.gif

AddHandler dlg.ClickApply, AddressOf DialogDemoOnApply

The DialogDemoOnApply method, which handles this event and is shown in Example 6-9 in C# and in Example 6-10 in VB.NET, gets an instance of the dialog box class that raised the event by casting the sender object as type DialogDemo. (Remember, even though sender is already of type DialogDemo, the compiler does not know this.) Once the reference to the DialogDemo dialog box is in hand, the value of the read-only TextOut property can be assigned to the label on the parent form and the EnableapplyButton property can be set to false, which disables the Apply button on the dialog box until the TextBox is modified again.

Examine the DialogDemo class more closely. Notice there is no member variable of type Form1 (the parent Form class), and no direct coupling between the dialog box class and the parent class. There is, however, a declared public event delegate called ClickApply:

figs/csharpicon.gif

public event EventHandler ClickApply;

figs/vbicon.gif

public event ClickApply as EventHandler

This delegate is of type EventHandler, which specifies that the event-handler methods added to the delegate will take two arguments: an object (typically called sender) and an argument of type EventArgs (typically called e).

Looking back at the event handler method added to the ClickApply delegate, you can see that it does in fact correspond to the required signature:

figs/csharpicon.gif

private void DialogDemoOnApply(object sender, System.EventArgs e)

figs/vbicon.gif

private sub DialogDemoOnApply(ByVal sender As System.Object, _
 ByVal e As System.EventArgs)




Programming. NET Windows Applications
Programming .Net Windows Applications
ISBN: 0596003218
EAN: 2147483647
Year: 2003
Pages: 148
Simiral book on Amazon

Flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net