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.

Tip

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#

image with no caption

//  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

image with no caption

'  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#

image with no caption

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

image with no caption

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:

image with no caption

DialogDemo dlg = new DialogDemo(  );

image with no caption

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:

image with no caption

private Button btnApply;
private TextBox txt;

image with no caption

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:

image with no caption

txt.TextChanged += new EventHandler(TextBoxChanged);

and the TextBoxChanged method looks like:

image with no caption

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:

image with no caption

AddHandler txt.TextChanged, AddressOf TextBoxChanged

and the TextBoxChanged method looks like:

image with no caption

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#

image with no caption

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

image with no caption

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:

image with no caption

btnApply.Click += new EventHandler(applyButtonOnClick);

image with no caption

AddHandler btnApply.Click, AddressOf applyButtonOnClick

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

image with no caption

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

image with no caption

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.

Tip

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:

image with no caption

dlg.ClickApply += new EventHandler(DialogDemoOnApply);

image with no caption

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:

image with no caption

public event EventHandler ClickApply;

image with no caption

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:

image with no caption

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

image with no caption

private sub DialogDemoOnApply(ByVal sender As System.Object, _
                              ByVal e As System.EventArgs)
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset