Inside Delphi 2006 (Wordware Delphi Developers Library)

Controls located in the Windows.Forms namespace are to .NET languages the same thing VCL is to Delphi and C++Builder languages — a collection of controls that allow us to build GUI applications.

Building Windows.Forms and VCL.NET applications inside the IDE is pretty much the same. Figure 29-15 and the following points illustrate this:

Figure 29-15: Building Windows.Forms applications in Delphi

There are also differences between the two frameworks:

Listing 29-23: The source code of a basic Windows.Forms form with a single Label component

unit MainForm; interface uses System.Drawing, System.Collections, System.ComponentModel, System.Windows.Forms, System.Data; type TMainForm = class(System.Windows.Forms.Form) { $REGION 'Designer Managed Code' } strict private /// <summary> /// Required designer variable. /// </summary> Components: System.ComponentModel.Container; Label1: System.Windows.Forms.Label; /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> procedure InitializeComponent; { $ENDREGION } strict protected /// <summary> /// Clean up any resources being used. /// </summary> procedure Dispose(Disposing: Boolean); override; private { Private Declarations } public constructor Create; end; [assembly: RuntimeRequiredAttribute(TypeOf(TMainForm))] implementation { $AUTOBOX ON } { $REGION 'Windows Form Designer generated code' } /// <summary> /// Required method for Designer support -- do not modify /// the contents of this method with the code editor. /// </summary> procedure TMainForm.InitializeComponent; begin Self.Label1 := System.Windows.Forms.Label.Create; Self.SuspendLayout; // // Label1 // Self.Label1.Location := System.Drawing.Point.Create(32, 32); Self.Label1.Name := 'Label1'; Self.Label1.TabIndex := 0; Self.Label1.Text := 'Label1'; // // TMainForm // Self.AutoScaleBaseSize := System.Drawing.Size.Create(5, 13); Self.ClientSize := System.Drawing.Size.Create(448, 270); Self.Controls.Add(Self.Label1); Self.Name := 'TMainForm'; Self.Text := 'Delphi for .NET Windows.Forms Application'; Self.ResumeLayout(False); end; { $ENDREGION } procedure TMainForm.Dispose(Disposing: Boolean); begin if Disposing then begin if Components <> nil then Components.Dispose(); end; inherited Dispose(Disposing); end; constructor TMainForm.Create; begin inherited Create; // // Required for Windows Form Designer support // InitializeComponent; // // TODO: Add any constructor code after InitializeComponent call // end; end.

Windows.Forms Application's Entry Point

As in .NET console applications, the entry point of a Windows.Forms application is the Main method. With Windows.Forms applications, the Main method contains a single line of code that creates the main form and calls the Run method of the global .NET Application object (instance of System.Windows.Forms.Application) to start the application and display the main form on screen. Listings 29-24A and 29-24B show the Main methods from a Delphi for .NET Windows.Forms application and a C# Windows.Forms application.

Listing 29-24A: The entry point of a Delphi for .NET Windows.Forms application

[STAThread] begin Application.Run(TWinForm.Create); end.

Listing 29-24B: The entry point of a C# Windows.Forms application

[STAThread] static void Main() { Application.Run(new WinForm()); }

Multicast Events

Among other differences, Windows.Forms and VCL frameworks differ in the fact that Windows.Forms controls can call multiple handlers in response to an event, while VCL components traditionally only fire a single event handler in response to an event.

In VCL applications, you can assign event handlers to an event using the assignment operator. If you assign the nil value to an event handler, you are removing the event handler from the event.

In Windows.Forms applications, you can add and remove multiple event handlers from an event using the Include and Exclude procedures. To see how this is done, take a look at Figure 29-16 and the example in Listing 29-25.

Figure 29-16: Windows.Forms application that illustrates multicast events

The Button1 and Button2 components in this example have their own event handlers that use the Show method of the MessageBox class to display a message dialog box. Button3 doesn't have its own Click event handler but calls the Click event handlers of Button1 and Button2.

The two event handlers are added to the Click event using the Include procedure in the form's OnLoad event (equivalent to the OnCreate event in VCL applications).

Listing 29-25: Assigning multiple event handlers to an event in a Delphi for .NET Windows.Forms application

procedure TWinForm.TWinForm_Load(sender: System.Object; e: System.EventArgs); begin // add event handlers of Button1 and Button2 to the // Click event of Button3 Include(Button3.Click, Button1_Click); Include(Button3.Click, Button2_Click); end; procedure TWinForm.Button2_Click(sender: System.Object; e: System.EventArgs); begin MessageBox.Show('Button2.Click', 'Message', MessageBoxButtons.OK, MessageBoxIcon.Information); end; procedure TWinForm.Button1_Click(sender: System.Object; e: System.EventArgs); begin MessageBox.Show('Button1.Click', 'Message', MessageBoxButtons.OK, MessageBoxIcon.Information); end;

In C#, you use the += to add event handlers to an event and –= to remove an event handler from an event (see Listing 29-26). Besides using these two operators, you have to instantiate the System.EventHandler delegate (dele- gates are covered in the next chapter) and pass to the EventHandler's constructor the name of the event handler you wish to add to the event.

Listing 29-26: Assigning multiple event handlers to an event in a C# Windows.Forms application

private void button1_Click(object sender, System.EventArgs e) { MessageBox.Show("button1.Click", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information); } private void button2_Click(object sender, System.EventArgs e) { MessageBox.Show("button2.Click", "Message", MessageBoxButtons.OK, MessageBoxIcon.Information); } private void WinForm_Load(object sender, System.EventArgs e) { button3.Click += new System.EventHandler(button1_Click); button3.Click += new System.EventHandler(button2_Click); }

Creating Windows.Forms Controls Dynamically

When creating controls dynamically, you have to manually set the control's parent, because the control is displayed on its parent control. In VCL, you display a control by setting a container control, like the main form, to its Parent property. In Windows.Forms applications, you add the component to the container control by calling the Add method of the container control's Controls collection.

Listing 29-27 shows how to dynamically create a Windows.Forms.Button control and how to display it on the main form. Figure 29-17 shows the result of the code in Listing 29-27.

Figure 29-17: A dynamically created Windows.Forms.Button calling a dynamically assigned event handler

Listing 29-27: Dynamically creating a Windows.Forms.Button control

procedure TWinForm.DynamicEvent(sender: System.Object; e: System.EventArgs); begin System.Windows.Forms.MessageBox.Show('The form will now close.', 'Message', MessageBoxButtons.OK, MessageBoxIcon.Information); Self.Close; end; procedure TWinForm.TWinForm_Load(sender: System.Object; e: System.EventArgs); var btn: Button; begin btn := Button.Create; btn.Location := System.Drawing.Point.Create(10, 10); // top and left btn.Size := System.Drawing.Size.Create(100, 25); // width and height btn.Text := 'Close'; Include(btn.Click, DynamicEvent); // equivalent to "Button.Parent := Self" in VCL Self.Controls.Add(btn); end;

Windows Forms MDI Essentials

Figure 29-18 shows a very simple Windows.Forms MDI application that we are going to build in this section.

Figure 29-18: A Windows.Forms MDI application

To have a Windows.Forms form act as an MDI parent, set its IsMDIContainer property to True. Then add a MainMenu and an OpenFileDialog component from the components category to it. To allow users to select multiple files with the OpenFileDialog component, set its MultiSelect property to True.

Now add another Windows Form to the project and drop a TextBox component on it. The Windows.Forms.TextBox control can act as the TEdit and TMemo component. To display an entire text file in the TextBox control, set its Multiline property to True and its Dock property to Fill, to have it cover the entire form.

To load an entire text file into the TextBox control, you have to use the System.IO.StreamReader class. Listing 29-28 shows how to load a text file into a TextBox control.

Listing 29-28: Loading an entire text file into a Windows.Forms.TextBox control

unit Child; interface uses System.Drawing, System.Collections, System.ComponentModel, System.Windows.Forms, System.Data, System.IO; type TChildForm = class(System.Windows.Forms.Form) public constructor Create; procedure LoadFile(FileName: string); end; implementation procedure TChildForm.LoadFile(FileName: string); var sr: System.IO.StreamReader; begin sr := System.IO.StreamReader.Create(FileName); try TextBox1.Text := sr.ReadToEnd; finally sr.Close; end; end;

The last tasks you have to do are create a File menu and the File ® Open item and write code that displays the OpenFileDialog and creates child forms. This code is displayed in Listing 29-29.

Listing 29-29: Creating child forms

procedure TWinForm.FileOpenItem_Click(sender: System.Object; e: System.EventArgs); var fileName: string; childForm: TChildForm; begin // display the OpenFileDialog if OpenFileDialog1.ShowDialog = System.Windows.Forms.DialogResult.OK then begin // browse through the selected files for fileName in OpenFileDialog1.FileNames do begin childForm := TChildForm.Create; // this changes the form to an mdi child form childForm.MdiParent := Self; childForm.Text := fileName; childForm.LoadFile(fileName); childForm.Show; end; // for end; // if ShowDialog end;

Категории