mod-Possible values for the Modifiers property Value C# equivalent Comments for Form inheritance Public public Any class, regardless of where and how it is defined, can modify the contr
Trang 1This ensures that any new objects added to the project will be created with thisnamespace With this change in place, we can create our base form.
Here we will just create the form and its controls Later in this section we will ate some infrastructure that will be useful in our derived forms later in the chapter
cre-CREATE THE BASEEDITDLG FORM
2 Add a new Form to the MyPhotoAlbum
project called “BaseEditDlg.”
The new class appears in the Solution Explorer window and the BaseEditDlg.cs [Design] window is displayed.
3 Add the three buttons to the form Assign
their settings and position as shown.
4 Add a Panel to the top of the form.
Note: The Modifiers property used here establishes the accessibility level of the control The three buttons use the default setting of Private The Protected setting creates a protected control so that it can
be modified in subclasses.
Settings Button Property Value
DialogResult OK Text &OK Reset (Name) btnReset
Text &Reset Cancel (Name) btnCancel
DialogResult Cancel Text &Cancel
Settings Property Value
BorderStyle FixedSingle Modifiers Protected
Trang 2The code generated here is similar to code we have seen for other forms in our cation The one exception is the panel1 control The three buttons are defined as
appli-private controls as have all the controls we created in earlier chapters The panel1
object is a protected control As we shall see, this will allow our child forms tomodify the settings of this panel, and in particular change its size to accommodate thedesired collection of controls
private System.Windows.Forms.Button btnOk;
private System.Windows.Forms.Button btnReset;
private System.Windows.Forms.Button btnCancel;
protected System.Windows.Forms.Panel panel1;
The cause of this change is the Modifiers property setting This is not an actualproperty in the C# sense, and does not appear in the documentation for the Button
class This setting appears in the Properties window within Visual Studio to allow theaccess level for a control to be set There are five possible values of this setting, asshown in the following table:
5 Set the properties for the BaseEditDlg
form to make it a dialog box.
CREATE THE BASEEDITDLG FORM (continued)
Settings Property Value
AcceptButton btnOk CancelButton btnCancel FormBorderStyle FixedDialog MaximizeBox False MinimizeBox False ShowInTaskBar False Size 300, 320
Trang 3Based on the table, we could have used either the Protected or Protected nal setting here Since there is no reason to prevent derived forms in external assem-blies from modifying the Panel control, the Protected value will work just fine.Before we move on, notice that our subclasses will not be able to add Click han-dlers for our private buttons The OK and Cancel buttons have assigned actions due
Inter-to their DialogResult setting When either button is clicked, the dialog is vated and the appropriate value returned We will require a way to save our modifiedsettings when the OK button is clicked, and we need a way to perform an action whenthe Reset button is clicked
deacti-As a solution, let’s add two protected methods that child classes can implement
to handle these situations We will create a SaveSettings method to store the ified values, and a ResetSettings method to handle a click of the Reset button.This continues our previous steps
mod-Possible values for the Modifiers property
Value C# equivalent Comments for Form inheritance
Public public Any class, regardless of where and how it is defined, can modify
the control This is not typically used, since you do not normally want any object to modify the location, size, or other internal control settings of your form.
Protected protected Any subclass of the form, regardless of where it is defined, can
modify the control.
Protected
Internal
protected internal
Any subclass of the form that is defined in the same assembly can modify the control.
Internal internal Any class in the same assembly, regardless of how it is defined,
can modify the control This is safer than public access, since you typically have control over the classes common to an assembly.
Private private No subclass can modify the control This is the default setting.
CREATE OVERRIDABLE METHODS FOR OK AND RESET BUTTONS
6 Create a protected virtual method for
resetting the form.
protected virtual void ResetSettings() {
// Subclasses override to reset form }
7 Add a Click handler for the Reset
button to invoke this new method.
private void btnReset_Click (object sender, System.EventArgs e) {
ResetSettings();
}
8 Create a protected virtual method for
saving the dialog settings when a form is deactivated This should return whether the save was successful.
protected virtual bool SaveSettings() {
// Subclasses override to save form return true;
}
Trang 4The ResetSettings and SaveSettings methods are now available to ourderived forms Compile your code to make the base form available for inheritance.Next, let’s create a derived form for editing a photograph’s settings The Base- EditDlg form will act as the parent of this new form.
A new form is derived from an existing form the same way that any new class is derivedfrom an existing class The base form is defined as the parent class of the new form. public class PhotoEditDlg : Manning.MyPhotoAlbum.BaseEditDlg
9 Override the OnClosing method for
the form to invoke this new method when the user clicks the OK button.
Note: This method is discussed in
detail in chapter 8 Note how the tings are saved only if a subclass has not cancelled the operation.
protected override void OnClosing (CancelEventArgs e)
{
if (!e.Cancel && (this.DialogResult == DialogResult.OK)) {
1 Open the Add New Item dialog to
add a new PhotoEditDlg form inherited from the existing
b Select Add Inherited Form…
from the Add menu.
c Enter the name “PhotoEditDlg.”
Trang 5View the code generated in the PhotoEditDlg.cs file, an excerpt of which follows.You will note that the new class is based on the BaseEditDlg class, and does not yetcontain any controls of its own.
#region Designer generated code
2 Click the Open button to display the
Inheritance Picker dialog.
This window is shown in the next step.
3 Define BasedEditDlg as the base
class for the new form.
Note: If you get an error here, it
likely means that your Dlg form was never compiled
BaseEdit-Visual Studio looks for inheritable forms in the existing assembly, so you must compile before you can inherit.
4 Click the OK button in the
Inheritance Picker dialog to create the class file and add it to the MyPhotoAlbum project.
Settings
Set the Text property to
“PhotoEditDlg” to distinguish this window from our base form.
A new file PhotoEditDlg.cs is added to the project and the PhotoEditDlg.cs [Design] window is displayed.
Note: Notice the small graphic on the existing
controls here This graphic indicates that these controls are inherited by the form.
DERIVE THE PHOTOEDITDLG FORM FROM THE BASEEDITDLG FORM (continued)
Trang 6/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
We will leave the topic of inherited forms for now and move on to specific trols for our PhotoEditDlg form Before we do, it is worth realizing how powerfulthis feature really is For example, a standard form for a database table could be cre-ated Applications that use this table can customize the form for their specific needs,
con-or libraries that extend the existing database can build a new fcon-orm based on the con-inal In many cases, changes to the original database can be encoded in the base class
orig-in such a way that no changes are required orig-in the orig-inherited forms
When you need a set of forms in your application based on a common concept
or theme, consider creating a base form from which other forms can be derived
In our MyPhotos application, we have already used the Label and TextBox classeswhile creating dialog boxes in chapter 8 Here we will look at these classes in a bitmore detail as we place them on our PhotoEditDlg form
To do this, we need to come up with some reasonable properties in our graph class that will facilitate the creation of these and other controls The followingfeatures will serve our purposes rather well:
Photo-•Caption—a caption for the photo We created this property in chapter 8.
•Date—the date the photograph was taken We will present this as a string on
our form here, and convert our dialog to use the DateTimePicker control inchapter 11
•Photographer—the person who took the photo For now, we will treat this
set-ting as a string Later in the book this setset-ting will be taken from a list of ble photographers
possi-•Notes—random notes or other comments about the photograph.
Trang 7A dialog to support these new settings is shown in figure 9.2 This dialog will be structed and discussed over the next few sections In this section we will create theinfrastructure required in the Photograph class to support these new settings, addthe required controls to the dialog, and invoke the dialog from the main form of our
con-MyPhotos class We also look at some of the settings and events provided by the
TextBox class for modifying the behavior or appearance of the control
We will start with the changes required in our Photograph class
In order to support the date, photograph, and notes settings in our photos, we need
to make a few changes This section adds these features to our Photograph object,
as well as the ability to read and write photographs, and update the Save and Open
methods in our PhotoAlbum class
We begin with some variables to hold these values and properties to provide nal access
exter-Set the version number of the MyPhotoAlbum library to 9.2.
Figure 9.2 Our Photo Properties dialog adds Label and Textbox controls to our inherited form.
ADD NEW MEMBERS TO THE PHOTOGRAPH CLASS
1 In the Photograph.cs file, add
some variables to hold the new settings.
Note: The DateTime structure used here represents a spe- cific day and time.
private string _caption;
private DateTime _dateTaken;
private string _photographer;
private string _notes;
Trang 8This code is similar to member fields and properties we have seen before, except forthe DateTime structure This structure represents an instant in time measured in
100 nanosecond units since 12:00:00 AM on January 1, 0001, with a maximumvalue of 11:59:59 PM on December 31, 9999 Each nanosecond unit of time is called
a tick Members of this structure allow you to add, subtract, format, and otherwise
manipulate date and time values A related TimeSpan structure represents an interval
of time You can look up these structures in the NET Framework documentation formore information on these types
With our fields and properties defined, we next need to store and retrieve thesevalues in the Save and Open methods of our PhotoAlbum class Since the Photo-graph class is becoming a bit more complex, we will create Read and Write methods
in this class to encapsulate the logic required The Write method will store a photointo an open StreamWriter object, while various Read methods will accept an open
StreamReader and return a Photograph object
In our PhotoAlbum class, we will use these new methods to save and load a newversion of our album file It will be version 92, to match the current section of the book.Let's continue our previous steps and create Read and Write methods in our
3 Add properties to set and
retrieve these values.
Note: A Caption property was added in chapter 8, and is not shown here.
public DateTime DateTaken {
get { return _dateTaken; } set { _dateTaken = value; } }
public string Photographer {
get { return _photographer; } set { _photographer = value; } }
public string Notes {
get { return _notes; } set { _notes = value; } }
ADD NEW MEMBERS TO THE PHOTOGRAPH CLASS (continued)
Trang 9ADD READ AND WRITE METHODS TO THE PHOTOGRAPH CLASS
4 Create a public Write method in the
Photograph.cs file to store a
Photograph into a given file.
public void Write(StreamWriter sw) {
// First write the file and caption sw.WriteLine(this.FileName);
sw.WriteLine(this.Caption);
// Write the date and photographer sw.WriteLine(this.DateTaken.Ticks); sw.WriteLine(this.Photographer);
// Finally, write any notes sw.WriteLine(this.Notes.Length);
sw.Write(this.Notes.ToCharArray()); sw.WriteLine();
}
5 Create a ReadVersion66 and
ReadVersion83 method to read in the data in the existing formats.
Note: These methods are static
since they create a new Photograph
instance from the data provided by the given stream.
static public Photograph ReadVersion66(StreamReader sr) {
String name = sr.ReadLine();
if (name != null) return new Photograph(name);
else return null;
}
static public Photograph ReadVersion83(StreamReader sr) {
String name = sr.ReadLine();
if (name == null) return null;
Photograph p = new Photograph(name); p.Caption = sr.ReadLine();
Trang 10Before we update the Save and Open methods in the PhotoAlbum class, a short cussion of our sudden use of the delegate keyword is in order.
dis-We briefly mentioned in chapter 1 that a delegate acts much like a functionpointer in C++ It identifies the signature for a method without actually defining amethod The advantage of C# delegates is that they are type safe It is impossible toassign a nonconforming method to a delegate
In our code, we create a delegate called ReadDelegate This delegate lates methods that accept a single StreamReader parameter and return a Photo- graph object It just so happens that this matches the signature of the three readmethods we created in the prior steps This delegate can be used to great advantagewhen opening an album Let’s see how this looks
encapsu-6 Create a static ReadVersion92
method to read in a Photograph for our new version 92 of an album file.
static public Photograph ReadVersion92(StreamReader sr) {
// Use ReadVer83 for file and caption Photograph p = ReadVersion83(sr);
if (p == null) return null;
// Read date (may throw FormatException) string data = sr.ReadLine();
long ticks = Convert.ToInt64(data); p.DateTaken = new DateTime(ticks);
// Read the photographer p.Photographer = sr.ReadLine();
// Read the notes size data = sr.ReadLine();
int len = Convert.ToInt32(data);
// Read the actual notes characters char[] notesArray = new char[len]; sr.Read(notesArray, 0, len);
p.Notes = new string(notesArray); sr.ReadLine();
return p;
}
7 Create a public delegate to use
when selecting the appropriate reader.
public delegate Photograph ReadDelegate(StreamReader sr);
ADD READ AND WRITE METHODS TO THE PHOTOGRAPH CLASS (continued)
con-c Read the photographer as a string.
d For the notes, read in the number
of characters and use this value to read an equivalent-sized array of characters This array can then be used to create a string.
e After the Notes property is set, a final ReadLine call is required to clear the final line in preparation for reading the next Photograph
object.
Trang 11UPDATE THE SAVE AND OPEN METHODS IN PHOTOALBUM CLASS
8 In the PhotoAlbum.cs source code
window, set the current version constant to 92.
private const int CurrentVersion = 92;
9 Modify the Save method to use the
new Photograph.Write method.
Note: The initial part of this
method creates the FileStream
and StreamWriter objects This code does not change, and is not shown here.
Similarly, the code for the
finally clause is also not shown.
public void Save(string fileName) {
try { sw.WriteLine(
_CurrentVersion.ToString());
// Store each photo separately foreach (Photograph photo in this) {
photo.Write(sw);
}
this._fileName = fileName;
} finally }
10 Modify the Open method to use the
new ReadDelegate delegate.
public void Open(string fileName) {
try { Clear();
this._fileName = fileName;
Photograph.ReadDelegate ReadPhoto;
11 In the switch statement, select the
correct version of the Photograph
reader.
How-to
Use a new statement to instantiate
a new version of the delegate for each version.
switch (version) {
case 66:
ReadPhoto = new Photograph.ReadDelegate(
Photograph.ReadVersion66); break;
case 83:
ReadPhoto = new Photograph.ReadDelegate(
Photograph.ReadVersion83); break;
case 92:
ReadPhoto = new Photograph.ReadDelegate(
Photograph.ReadVersion92); break;
default:
// Unknown version or bad file throw (new IOException( .)); }
Trang 12This neat little use of delegates makes our code much more readable A delegateinstance is declared just like any other variable, except that in this case the type is ourdelegate.
ReadPhoto = new Photograph.ReadDelegate(Photograph.ReadVersion92); break;
The delegate is then used like any other function call to invoke the assigned method. // Read each photograph in the album
9.2.2 C REATING THE P HOTO E DIT D LG PANEL AREA
Looking back at the PhotoEditDlg dialog we wish to create, let’s focus on the
Panel control at the top of the form In chapter 7 we made use of the Panel classfor its drawing and scrolling capabilities Here, we will use this class as a containerfor other controls to improve the overall appearance of our form While we will not
12 Use the reader delegate to load the
individual photographs.
Note: The code for the finally
clause remains the same and is not shown here.
// Read each photograph in the album Photograph p = ReadPhoto(sr);
while (p != null) {
this.Add(p);
p = ReadPhoto(sr);
} } finally }
UPDATE THE SAVE AND OPEN METHODS IN PHOTOALBUM CLASS (continued)
Trang 13enable scrolling in our panel, realize that controls can be placed outside of the visibleportion of a panel and made accessible via the automated scroll bars discussed inchapter 7.
We have used the Label and TextBox controls previously in our program, solet’s update our panel before we talk about these classes in more detail As you recall,the Panel object is inherited from the base form, but is modifiable by our class since
it has a protected access level
CREATE THE PANEL AREA OF THE PHOTOEDITDLG FORM
1 In the PhotoEditDlg.cs [Design] window,
modify the Text property for the new dialog to be “Photo Properties.”
2 Add the four Label controls to the left
side of the panel, as shown in the graphic
Resize the panel control if necessary Set the properties for each label as shown.
Note: In this step you are placing the
con-trols inside the Panel , rather than inside the Form This is an important distinction
Settings Label Property Value
label1 Text Photo &File:
TextAlign MiddleRight label2 Text Cap&tion:
TextAlign MiddleRight label3 Text &Date Taken:
TextAlign MiddleRight label4 Text &Photographer:
TextAlign MiddleRight
Trang 14Note that the labels and text boxes here are defined within the Panel control, ratherthan within the form In the InitializeComponent method, the controls areadded to the Panel object much like we have seen other controls added to the Form
class in previous chapters
this.panel1.Controls.AddRange(new System.Windows.Forms.Control[] { this.txtPhotographer,
3 Add the four TextBox controls to the right
side of the panel Position and size these controls as in the graphic, and use the following properties.
Note: The txtPhotoFile text box plays a gray background to indicate it is read-only.
dis-4 Set the tab order for these new controls.
How-to
In the tab order view of the page, click controls within the panel in order Press the Esc key when finished.
Note: As you can see in the graphic, the
controls within the panel are numbered to indicate both the tab index of the panel and of the specific control.
CREATE THE PANEL AREA OF THE PHOTOEDITDLG FORM
Settings TextBox Property Value
Photo File (Name) txtPhotoFile
ReadOnly True Text
Caption (Name) txtCaption
Text Date (Name) txtDate
Text Photographer (Name) txtPhotographer
Text
Trang 15The setting of the tab order in the final step, which internally assigns the TabIndex
property for each control, is very important here We could have set these valuesexplicitly in steps 2 and 3, but the method in step 4 allowed us to set all controls atonce Since the Label and TextBox controls are located within the Panel object,the tab order defined applies only within the panel, so the TabIndex values for ourlabels and text boxes start at zero
While label controls do not participate in the tab order, their TabIndex setting
is still utilized When you tab to or activate a label, the next control in the tab orderwill receive focus This is the same behavior provided by the MFC CStatic class inVisual C++
.NET Table 9.1 Label class
The Label class is a control that displays a text string or image within a form This class is part of the of the System.Windows.Forms namespace, and inherits from the Control class
A Label object can be assigned a tab index, but when activated the next control in the tab order will always receive focus See NET Table 4.1 on page 104 for a list of members inher- ited from the Control class.
Public Properties
AutoSize Gets or sets whether the label should
automatically resize to display its contents BorderStyle Gets or sets the border for the label, taken from
the BorderStyle enumeration The default is
None FlatStyle Gets or sets the flat style for the label, using the
FlatStyle enumeration The default is
Standard Image Gets or sets the image to appear on the label ImageList Gets or sets an ImageList object to associate
with the label The ImageIndex property determines which image is displayed on the label.
PreferredHeight Gets the height of the control, in pixels,
assuming a single line of text is displayed PreferredWidth Gets the width of the control, in pixels, assuming
a single line of text is displayed.
TextAlign Gets or sets the text alignment to use for text in
the control.
UseMnemonic Gets or sets whether an ampersand (&) in the
Text property is interpreted as an access key prefix character.
Trang 16This tab order behavior is especially relevant for the assigned access key, alsocalled a mnemonic For example, the ampersand character “&” in the Photo File labeldefines the ‘F’ character as the access key Typing the keystroke Alt+F sets the focus
to this label When you do this, the txtPhotoFile control actually receives thefocus Similarly, typing Alt+P for the Caption label will set the focus to the txtCap- tion control Such mnemonics are very useful for users, myself included, who prefer
to avoid the mouse and keep their fingers on the keyboard
Labels include other features as well, of course As we saw in chapter 8, they candisplay a border and define an alignment for displayed text These and other features
of the Label class are summarized in NET Table 9.1 The Label class is also theparent of the LinkLabel class, which adds the ability to perform an action when thetext on the label is clicked, similar to an HTML link in a web browser We will usethe LinkLabel class in chapter 18 while discussing how to include ActiveX controls
on a form
We will use Label objects again in future sections For now, let’s move on to cuss some of the features of our TextBox controls, and the TextBox class in general
The TextBox controls on our form are used to display various properties of the
Photograph object We have already created the text box controls within the panelarea In this section we create the text box for displaying the Photograph.Notes
property in our dialog, and implement the protected members we defined in our baseclass earlier in the chapter
As we saw in the previous section, text boxes can be editable or read-only In someways a read-only text box is similar to a Label object with a 3D border The majordifference is that a text box supports cut and paste operations, while a label does not.The existing CaptionDlg form in our application used a 3D label to illustrate thispoint, so you can verify this for yourself if you prefer
As a result, a read-only TextBox should be used when displaying text that a usermay wish to copy This, in fact, is why our PhotoEditDlg form uses a read-only
TextBox to display the photograph’s file name
The TextBox class is based on the TextBoxBase class, which provides much ofthe core functionality for text controls An overview of this base class appears in NETTable 9.2
Trang 17As shown in the table, the TextBoxBase class provides a Multiline property thatindicates whether a derived control can accept multiple lines of text The bottom part
of our PhotoEditDlg form is designed to show off such a text box This control
.NET Table 9.2 TextBoxBase class
The TextBoxBase class is a control that displays editable text and can interact with the
Clipboard class to permit cut and paste operations This class is part of the of the tem.Windows.Forms namespace, and inherits from the Control class Both the TextBox
Sys-and RichTextBox classes are derived from this abstract class See NET Table 4.1 on page
104 for a list of members inherited from the Control class, and NET Table 9.3 on page 288 for an overview of the TextBox class.
Public Properties
AcceptsTab Gets or sets whether a multiline text box displays a Tab
character or moves focus to the next control when the Tab key is pressed.
CanUndo Gets or sets whether the user can undo the previous edit
performed in the text box.
Lines Gets or sets the array of strings representing the lines of
text in the control.
MaxLength Gets or sets the maximum number of characters the control
will accept.
Multiline Gets or sets whether this is a multiline text box.
ReadOnly Gets or sets whether the text is read-only.
SelectedText Gets or sets the currently selected text in the control The
SelectedStart property indicates the location of the first selected character.
WordWrap Gets or sets whether a multiline control automatically
wraps to the next line as required.
Public Methods
AppendText Appends a string to the existing text in the control.
Copy Copies the current text into the Clipboard Paste Replaces the current selection with the contents of the
Clipboard.
ScrollToCaret Ensures the current caret position is visible in a multiline
text box.
SelectAll Selects all text in the control The Select method can be
used to select a substring.
Undo Undoes the last edit operation in the text box.
Public Events
Changed
AcceptsTab-Occurs when the AcceptsTab property changes.
Changed
Multiline-Occurs when the Multiline property changes.
Trang 18displays descriptive text about the photo, and automatically scrolls if the textbecomes too long The following steps add this control to our dialog:
Our form is now ready, except for the internal logic to process the user’s changes.Since our dialog is intended to edit a Photograph object within a PhotoAlbum
collection, we need a reference to the associated PhotoAlbum object within the log We should also implement the methods necessary to handle the OK and Resetbuttons, namely the ResetSettings and SaveSettings methods provided by the
dia-BaseEditDlg class
The following steps detail these changes:
ADD A MULTILINE T EXTBOX TO THE PHOTOEDITDLG FORM
1 Add the Notes label to the
PhotoEditDlg form in the PhotoEditDlg.cs [Design]
window
The AutoSize property causes the label to resize to exactly fit its Text value.
2 Add the multiline TextBox
control to the form.
Note: The Multiline property must be set to true
before the control can be resized to contain multiple lines
of text.
The AcceptsReturn property causes the control to treat an Enter key as a new line rather than allowing the parent form to invoke the OK button.
Settings
Property Value
AutoSize True TabIndex 4 Text Notes:
Settings Property Value
(Name) txtNotes AcceptsReturn True Multiline True ScrollBars Vertical TabIndex 5 Text
Trang 19Our dialog is complete, at least for now Applications can use it to display and modifyinformation about a photograph The one exception is the date a photograph wastaken While it is certainly possible to convert a string provided by the user into a
DateTime structure, this is not really the best way to specify a date on a form Instead,the DateTimePicker control is provided especially for this purpose We will look atthis control in chapter 11, and simply ignore the value of txtDate for now
The next step is to use this new dialog in our main application This is the topic
of the next section
INTERACTING WITH THE PHOTOALBUM OBJECT
3 In the PhotoEditDlg.cs file add a
private PhotoAlbum variable to hold the album containing the photo to display.
private PhotoAlbum _album;
4 Modify the constructor to accept
a PhotoAlbum parameter.
public PhotoEditDlg(PhotoAlbum album)
{
5 Within the constructor, set the
album variable and call
ResetSettings to initialize the dialog’s controls.
// This call is required InitializeComponent();
// Initialize the dialog settings _album = album;
ResetSettings();
}
6 Implement the ResetSettings
method to set the controls to their corresponding settings in the current photograph.
protected override void ResetSettings() {
Photograph photo = _album.CurrentPhoto;
if (photo != null) {
txtPhotoFile.Text = photo.FileName;
txtCaption.Text = photo.Caption;
txtDate.Text = photo.DateTaken.ToString();
txtPhotographer.Text = photo.Photographer; this.txtNotes.Text = photo.Notes;
} }
7 Implement SaveSettings to
save the contents of the form to the current photograph.
Note: Here, the settings are
always stored successfully, so this method always returns
photo.Caption = txtCaption.Text;
// Ignore txtDate setting for now photo.Photographer = txtPhotographer.Text; photo.Notes = txtNotes.Text;
}
return true;
}
Trang 209.2.4 A DDING P HOTO E DIT D LG TO OUR MAIN FORM
Now that our new dialog is ready, we need to display it in our MyPhotos application.This section integrates the dialog into our application, much like we integrated the
CaptionDlg form in chapter 8
The CaptionDlg form does present a slight problem, in that it already allowsthe caption to be edited, just like our new PhotoEditDlg form We could keep thisdialog around and provide two ways to edit a photograph’s caption This might be alittle confusing to users, so we will instead remove CaptionDlg from our application.The step to remove this dialog follows We will integrate the PhotoEditDlg dia-log into our application in a moment
Set the version number of the MyPhotos application to 9.2.
With the caption dialog gone, our way is clear to display the PhotoEditDlg formfrom our main window We will reuse the menuCaption menu for this purpose,renamed and revamped by the following steps:
REMOVE THE CAPTIONDLG FORM
1 In the Solution Explorer window, delete
the CaptionDlg form.
Alternately
Click on the file and press the Delete key.
After clicking OK, the CaptionDlg.cs class is removed from the project and deleted from the file system.
How-to
a Right-click on the CaptionDlg.cs file.
b Select Delete from the popup menu.
c Click OK in the confirmation box.
Trang 21Since the dialog itself handles the initialization and storage of any changes made by theuser, and the using statement disposes of the dialog when we are finished, there is notmuch work required by our handler When the user clicks OK, we mark that thealbum has changed and update the status bar with any new caption entered by the user.
DISPLAY THE PHOTOEDITDLG FORM FROM THE MAIN WINDOW
2 Double-click the MainForm.cs file in
the Solution Explorer window.
The Windows Forms Designer window appears for this form.
3 Modify the properties for the Caption
menu item under the Edit menu.
Note: We could elect to use this
menu under its previous name This could prove confusing in the future, so
we instead rename the control in line with its new purpose.
4 Rename the Click event for this
menu to menuPhotoProp_Click
5 Replace the old handler with an
implementation to display the
if (_album.CurrentPhoto == null) return;
using (PhotoEditDlg dlg = new PhotoEditDlg(_album)) {
if (dlg.ShowDialog() == DialogResult.OK) {
_bAlbumChanged = true;
sbpnlFileName.Text = _album.CurrentPhoto.Caption; statusBar1.Invalidate();
} } }
6 Update the Popup event handler for
the Edit menu to use the new menu.
private void menuEdit_Popup (object sender, System.EventArgs e) {
menuPhotoProp.Enabled
= (_album.Count > 0);
}
Settings Property Value
(Name) menuPhotoProp Text &Photo
Properties…
Trang 22So let’s see if your code actually works Compile and run the application and open
a previously saved album file Display the Photo Properties dialog Note in particularthe following features:
•The differences between the read-only and editable text boxes
•Label text cannot be highlighted, while text within text boxes can, even whenread-only
•Use the access key for a label and notice how the following text box receivesfocus
•Press the Enter key while editing a single-line text box The dialog behaves as ifyou had clicked the OK button
•Press the Enter key while editing within the Notes text box Since we set the
AcceptsReturn property to true, this adds a new line within the Notes boxand does not deactivate the window
•Right-click on any text box The default context menu will appear This text menu contains various commands for editing text, and is shown infigure 9.3 The items in this menu correspond to methods in the TextBox- Base class, as shown in NET Table 9.2
con-While our form is working just fine, there are some features missing that might makeour dialog a little more friendly These are the subject of the next section
9.2.5 U SING T EXT B OX CONTROLS
So let’s add some interesting features to our text boxes Most of the events for Box controls are inherited from the Control and TextBoxBase classes Members
Text-Figure 9.3 The standard context menu for Text- Box controls, shown here for the Date Taken text box, disables commands that are not currently available.
Trang 23specific to the TextBox class appear in NET Table 9.3 Here we will look moreclosely at the KeyPress event and the TextChanged event.
The keyboard events inherited from the Control class are especially interesting,and consist of the KeyDown, KeyPress, and KeyUp events These events are inheritedfrom the Control class, and occur when a key on the keyboard is pushed down andreleased while the control has focus The KeyDown event occurs when the key is firstpressed The KeyPress event activates while the key is held down and repeats whilethe key remains held down The KeyUp event occurs when the key is released Theseevents can be used to fine-tune your interfaces as the user types on the keyboard
We will look at the keyboard events in more detail in chapter 12, but let’s do a quickexample here Suppose we wanted the Caption property to only contain letters ornumbers No punctuation characters and no symbols The KeyPress event receiveskeyboard characters as they are typed, and allows the event handler to handle orignore them The KeyPressEventArgs class is used with this event, and provides a
KeyChar property to get the character pressed, and a Handled property to get or setwhether the character has been handled If Handled is set to true, then the controlwill not receive the character
The obvious, albeit incorrect, way to implement such a handler would be as follows: private void txtCaption_KeyPress(object sender, KeyPressEventArgs e) {
.NET Table 9.3 TextBox class
The TextBox class represents a TextBoxBase control that displays a single font This control
is part of the System.Windows.Forms namespace, and inherits from the TextBoxBase trol Through its parent class, text boxes can support single or multiple lines, and interact with the clipboard to cut, copy, or paste text.
con-Public Properties
AcceptsReturn Gets or sets whether the Enter key in a multiline
text box adds a new line of text or activates the default button for the form.
CharacterCasing Gets or sets how the control modifies the case
of entered characters This can be used to display all uppercase or lowercase letters in the text box.
PasswordChar Gets or sets the character used to mask the text
display in the control When this property is set, cutting or copying to the clipboard is disabled ScrollBars Gets or sets which scrollbars should appear in a
multiline text box.
TextAlign Gets or sets how displayed text is aligned within
the control.
Public Events TextAlignChanged Occurs when the TextAlign property has
changed.
Trang 24// Ignore all non-alphanumerics – not our approach
e.Handled = !(Char.IsLetter(c) || Char.IsDigit(c));
}
This implementation uses members of the System.Char class to see if the category
of the character is a letter or number It may look good, but it also causes all othercharacters to be ignored by the control, such as spaces and backspaces Clearly, this isnot what we want
Instead, we will allow all control and white space characters past our event handler.This will permit the keyboard shortcuts to work, and also allows spaces in our captions
The caption text box will only receive letters, digits, white space, and all control acters This may or may not be a good idea, by the way, since a caption such as “one-way street” is now not permitted, since the dash ‘-’ is a punctuation character Feelfree to remove this handler if you do not want this behavior in your program.Another feature we could add to our dialog is to display the caption for the pho-tograph in the title bar Of course, this caption can be edited, and we would not wantthe text box and the title bar to display different values
char-The TextChanged event occurs as text is entered, and can be used here to updatethe title bar while the user is typing We could also implement this feature using the
KeyPress event we just saw, but would have to deal with the delete and backspacekeys as well as some text-editing controls The TextChanged approach is a bit morestraightforward
Let’s continue our previous steps and make this change
ADD KEYPRESS EVENT HANDLER FOR TXTCAPTION CONTROL
1 In the PhotoEditDlg.cs Design
window, add a KeyPress event for the txtCaption text box control.
private void txtCaption_KeyPress (object sender, KeyPressEventArgs e) {
2 Implement this handler to only
permit letters and numbers to appear in captions.
char c = e.KeyChar;
e.Handled = !(Char.IsLetterOrDigit(c) || Char.IsWhiteSpace(c)
|| Char.IsControl(c));
}
Trang 25Compile and run your application to view these new changes Verify that the captioncan contain only letters and numbers, and that the title updates automatically as thecaption is modified.
TRY IT! As an exercise in using some of the methods available to TextBox controls,
see if you can create the standard context menu for text boxes manually andassign it to the Notes control You will need to add a ContextMenu ob-ject to the form and assign it to the txtNotes.ContextMenu property Assigning this property automatically disables the default context menu.Add the eight menu items to the menu, namely Undo, a separator, Copy,Cut, Paste, Delete, another separator, and Select All To make your menudifferent than the standard one, also add a Clear menu item at the end ofthe context menu to clear the text in the box
To process this menu, you will need a Popup event handler for themenu itself to enable or disable the menu items as appropriate You willneed to use the CanUndo, SelectedText, SelectionLength, and Se- lectionStart properties, and the Copy, Cut, Paste, SelectAll, and
Undo methods as part of your implementation
If you run into difficulties, visit the book’s web site and download thecode required for this change
This ends our discussion of Label and TextBox objects for now We will see theseobjects again in the next section and elsewhere in the book Our next topic will createthe Album Properties dialog box as a way to introduce the button classes in the NETFramework
So just what is a button, exactly? For graphical interfaces, a button is a control thatestablishes a specific state, typically some form of on or off Buttons are used to per-form immediate actions in an interface, define the behavior for a specific feature, or
UPDATE TITLE BAR DURING TXTCAPTION MODIFICATION
3 Add a TextChanged event
for the txtCaption text box control.
How-to
This is the default event for text boxes, so you can just double-click the control.
private void txtCaption_TextChanged (object sender, System.EventArgs e) {
4 Modify the title bar to
include the modified text from the control.
this.Text = String.Format(
"{0} - Photo Properties", txtCaption.Text);
}