- •brief contents
- •about this book
- •The Windows Forms namespace
- •Part 1: Hello Windows Forms
- •Part 2: Basic Windows Forms
- •Part 3: Advanced Windows Forms
- •Who should read this book?
- •Conventions
- •Action
- •Result
- •Source code downloads
- •Author online
- •acknowledgments
- •about .NET
- •Casting the .NET
- •Windows Forms overview
- •about the cover illustration
- •Hello Windows Forms
- •1.1 Programming in C#
- •1.1.1 Namespaces and classes
- •1.1.2 Constructors and methods
- •1.1.3 C# types
- •1.1.4 The entry point
- •1.1.5 The Application class
- •1.1.6 Program execution
- •1.2 Adding controls
- •1.2.1 Shortcuts and fully qualified names
- •1.2.2 Fields and properties
- •1.2.3 The Controls property
- •1.3 Loading files
- •1.3.1 Events
- •1.3.2 The OpenFileDialog class
- •1.3.3 Bitmap images
- •1.4 Resizing forms
- •1.4.1 Desktop layout properties
- •1.4.2 The Anchor property
- •1.4.3 The Dock property
- •1.5 Recap
- •2.1 Programming with Visual Studio .NET
- •2.1.1 Creating a project
- •Action
- •Result
- •2.1.2 Executing a program
- •Action
- •Result
- •2.1.3 Viewing the source code
- •View the code generated by Visual Studio .NET
- •Action
- •Result
- •2.2 Adding controls
- •2.2.1 The AssemblyInfo file
- •Action
- •Results
- •2.2.2 Renaming a form
- •Action
- •Result
- •2.2.3 The Toolbox window
- •Action
- •Result
- •2.3 Loading files
- •2.3.1 Event handlers in Visual Studio .NET
- •Action
- •Result
- •2.3.2 Exception handling
- •Action
- •Result
- •Action
- •Results and Comments
- •2.4 Resizing forms
- •2.4.1 Assign the Anchor property
- •Action
- •Result
- •2.4.2 Assign the MinimumSize property
- •Action
- •Result
- •2.5 Recap
- •Basic Windows Forms
- •Menus
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •3.3 Click events
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •3.5 Context menus
- •Action
- •Result
- •Action
- •Result
- •3.6 Recap
- •Status bars
- •4.1 The Control class
- •4.2 The StatusBar class
- •Action
- •Result
- •Action
- •Result
- •4.3.1 Adding panels to a status bar
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •4.5 Recap
- •Reusable libraries
- •5.1 C# classes and interfaces
- •5.2 Class libraries
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •5.3 Interfaces revisited
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •5.4 Robustness issues
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Common file dialogs
- •Action
- •Results
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.3 Paint events
- •Action
- •Result
- •Action
- •Result
- •6.4 Context menus revisited
- •Action
- •Result
- •Action
- •Result
- •6.5 Files and paths
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.6 Save file dialogs
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •6.7 Open file dialogs
- •Action
- •Result
- •Action
- •Result
- •6.8 Recap
- •Drawing and scrolling
- •7.1 Form class hierarchy
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •7.4 Panels
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Dialog boxes
- •8.1 Message boxes
- •Action
- •Result
- •Action
- •Result
- •8.1.4 Creating A YesNoCancel dialog
- •Action
- •Result
- •Action
- •Result
- •8.2 The Form.Close method
- •8.2.1 The relationship between Close and Dispose
- •Action
- •Result
- •8.3 Modal dialog boxes
- •Action
- •Result
- •Action
- •Result
- •8.3.2 Preserving caption values
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Basic controls
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •9.1.2 Creating a derived form
- •Action
- •Result
- •9.2 Labels and text boxes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •9.3.6 Adding AlbumEditDlg to our main form
- •Action
- •Result
- •Action
- •Result
- •9.4 Recap
- •List controls
- •10.1 List boxes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.2 Multiselection list boxes
- •10.2.1 Enabling multiple selection
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.3 Combo boxes
- •Action
- •Result
- •Action
- •Result
- •10.4 Combo box edits
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •10.5 Owner-drawn lists
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •More controls
- •Action
- •Result
- •Action
- •Result
- •11.2 Tab pages
- •Action
- •Result
- •Action
- •Result
- •11.3.1 Dates and times
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •11.5 Recap
- •A .NET assortment
- •12.1 Keyboard events
- •Action
- •Result
- •Action
- •Result
- •12.2 Mouse events
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.3 Image buttons
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.4 Icons
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •12.5 Recap
- •Toolbars and tips
- •13.1 Toolbars
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •13.4.2 Creating tool tips
- •Action
- •Result
- •Action
- •Result
- •Advanced Windows Forms
- •List views
- •14.2 The ListView class
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •14.2.3 Populating a ListView
- •Action
- •Result
- •Action
- •14.3 ListView columns
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •14.6 Recap
- •Tree views
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.3 Dynamic tree nodes
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.4 Node selection
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •15.5 Fun with tree views
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Multiple document interfaces
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.3 Merged menus
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.4 MDI children
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •16.5 MDI child window management
- •Action
- •Result
- •Action
- •Result
- •16.6 Recap
- •Data binding
- •17.1 Data grids
- •Action
- •Result
- •Action
- •Result
- •17.2 Data grid customization
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Odds and ends .NET
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •18.2 Timers
- •Action
- •Result
- •Action
- •Result
- •18.3 Drag and drop
- •Action
- •Result
- •Action
- •Result
- •18.4 ActiveX controls
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •Action
- •Result
- •18.5 Recap
- •C# primer
- •A.1 C# programs
- •A.1.1 Assemblies
- •A.1.2 Namespaces
- •A.2 Types
- •A.2.1 Classes
- •A.2.2 Structures
- •A.2.3 Interfaces
- •A.2.4 Enumerations
- •A.2.5 Delegates
- •A.3 Language elements
- •A.3.1 Built-in types
- •A.3.2 Operators
- •A.3.3 Keywords
- •A.4 Special features
- •A.4.1 Exceptions
- •A.4.2 Arrays
- •A.4.3 Main
- •A.4.4 Boxing
- •A.4.5 Documentation
- •.NET namespaces
- •B.1 System.Collections
- •B.2 System.ComponentModel
- •B.3 System.Data
- •B.4 System.Drawing
- •B.5 System.Globalization
- •B.6 System.IO
- •B.7 System.Net
- •B.8 System.Reflection
- •B.9 System.Resources
- •B.10 System.Security
- •B.11 System.Threading
- •B.12 System.Web
- •B.13 System.Windows.Forms
- •B.14 System.XML
- •Visual index
- •C.1 Objects
- •C.2 Marshal by reference objects
- •C.3 Components
- •C.4 Common dialogs
- •C.7 Event data
- •C.8 Enumerations
- •For more information
- •bibliography
- •Symbols
- •Index
BIND THE PHOTO TAB CONTROLS TO PROPERTIES IN THE PHOTOGRAPH CLASS
|
Action |
Result |
|
|
|
1 |
Locate the OnLoad override in |
protected override void OnLoad(EventArgs e) |
|
the MainForm.cs code window. |
{ |
|
|
. . . |
|
|
|
2 |
Assign data bindings to the |
// Bind data for the Photo tab |
|
controls on the Photo tab page. |
txtFileName.DataBindings. |
|
Note: Of critical importance |
Add("Text", _album, "FileName"); |
|
txtCaption.DataBindings. |
|
|
here is the fact that we use the |
Add("Text", _album, "Caption"); |
|
same PhotoAlbum instance |
txtPhotographer.DataBindings. |
|
Add("Text", _album, "Photographer"); |
|
|
throughout the life of our appli- |
|
|
dtpDateTaken.DataBindings. |
|
|
cation. Since we bind these |
Add("Value", _album, "DateTaken"); |
|
controls as the main form is |
txtNotes.DataBindings. |
|
loaded, the value of our album |
|
|
Add("Text", _album, "Notes"); |
|
|
cannot change unless we also |
|
|
pboxPhoto.DataBindings. |
|
|
rebind the controls to the new |
Add("Image", _album, "Image"); |
|
value. |
} |
|
|
|
The controls are now bound to the appropriate properties of the Photograph objects contained by the PhotoAlbum instance. Take, for example, the DateTimePicker control. We bind the Value property of this control to the DateTaken property of the active Photograph object in the _album collection with the following code:
dtpDateTaken.DataBindings.Add("Value", _album, "DateTaken");
The DataBindings collection supports the standard Add method to place a Binding object in the list. We could have created the Binding object explicitly with the following code:
Binding theBind = new Binding("Value", _album, "DateTaken");
dtpDateTaken.DataBindings.Add(theBind);
Instead, since we do not need the Binding instance here, we used an override for the Add method that accepts the constructor parameters for this object explicitly.
Note that the Photograph.DateTaken property is a DateTime value, which happens to match the type of the DateTimePicker.Value property. In fact the type of all our bindings, including the Image property for the PictureBox control, matches the bound property in the Photograph object. The .NET Framework will attempt to convert between the binding value and the bound value, but in our case conversion is not necessary. As we mentioned earlier, the Format and Parse events can be used to specify the conversion explicitly.
It is worth mentioning once again that any property of a control can be bound. For example, we could add a MatteColor property to our Photograph object, and bind the background color, the BackColor property, of the PictureBox or even the TabPage itself to this color. We will not do this here, and I should probably caution
SIMPLE DATA BINDING |
593 |
you not to get too carried away with such features both in your data and in your applications. In some situations, such as a picture frame ordering interface, this type of feature could be very useful.
This code will compile and run and show a result similar to figure 17.7. Some work is still required to update the controls when the album changes or the Next or Prev button is pressed, and the PictureBox control has a size mode of Normal so that only the upper left corner of the image is shown. We will address these issues as we go along.
Before we do, it is also worth mentioning here that Visual Studio .NET provides direct graphical support for data binding when using a database or other class that supports both the IList and IComponent interfaces. In particular, the values from a database can be bound to a control during design time using the (DataBindings) setting in the Properties window. This is beyond the scope of this book, but worth keeping in mind as you develop more complex applications.
Figure 17.7 In this version, the controls automatically bind to the active Photograph selected in the DataGrid control. Note that only a portion of the image appears in the PictureBox control here.
17.4.3UPDATING DATA BOUND CONTROLS
With our controls bound, our next task is to properly update them as the selected album changes. We also need to hook up the Next and Prev buttons so that they display the next or previous photo from the current album. Doing this requires the
BindingManagerBase class.
A summary of this class appears in .NET Table 17.7. An instance of this class is created for each data source active in an application, and stored in a BindingContext instance associated with a Control object. Normally, the BindingContext created for the Form object is used, although a BindingContext can be attached to any Control. For example, a BindingContext can be created for a GroupBox, Panel, or other parent control to contain the data sources for all controls within the container.
594 |
CHAPTER 17 DATA BINDING |
As indicated in the table, the BindingManagerBase class is an abstract class. When a control is bound, the framework automatically creates the appropriate subclass of this object. A CurrencyManager instance is created for objects that support the IList interface, while a PropertyManager is created for single-value objects.
Two of the more commonly used members of the BindingManagerBase class are the Current and Position properties. The Current property retrieves the object currently used to bind controls, while the Position property manages the index of this object. In our application, this means that the Current property retrieves the Photograph currently displayed by our controls, while the Position property is used to assign or retrieve the index of the current Photograph object.
.NET Table 17.7 BindingManagerBase class
The BindingManagerBase class represents a data source bound to one or more controls within a Windows Forms control. This class enables synchronization of all controls with a property bound to the associated data source. This class is part of the System.Windows.Forms namespace.
This class is abstract and cannot be instantiated. The CurrencyManager class is used for all data sources that support the IList interface, while the PropertyManager class is used for all single-value data sources. Also note that most of the members listed here are abstract as well, and must be overridden by a derived class.
|
Bindings |
Gets the collection of bindings managed by this |
|
|
|
object. |
|
|
Count |
Gets the number of rows managed by this object. |
|
Public Properties |
Current |
Gets the current, or active, list item in the |
|
|
|||
|
|
associated data source. |
|
|
Position |
Gets or sets the position, or index, of the item to |
|
|
|
consider active in the associated data source. |
|
|
|
|
|
|
AddNew |
Adds a new item of the appropriate type to the |
|
|
|
associated data source. |
|
|
CancelCurrentEdit |
Cancels the current edit, if any, of the associated |
|
|
|
data source. |
|
|
EndCurrentEdit |
Completes the current edit, if any, of the associated |
|
|
|
data source. |
|
Public Methods |
GetItemProperties |
Retrieves the collection of PropertyDescriptor |
|
|
|||
|
|
objects from the associated data source. |
|
|
RemoveAt |
Deletes the item at the specified index from the |
|
|
|
associated data source. |
|
|
ResumeBinding |
Resumes data binding for the data source. |
|
|
SuspendBinding |
Suspends data binding for the data source. |
|
|
|
|
|
Public Events |
CurrentChanged |
Occurs when the the Current property changes. |
|
PositionChanged |
Occurs when the the Position property changes. |
||
|
|||
|
|
|
SIMPLE DATA BINDING |
595 |
We can make immediate use of the Position property to implement the Next and Prev buttons for our application.
HANDLE THE CLICK EVENTS FOR THE NEXT AND PREV BUTTONS
|
Action |
Result |
|
|
|
1 |
Create a new EnablePhotoButtons |
private void EnablePhotoButtons |
|
method to enable or disable the Next |
(BindingManagerBase bm) |
|
and Prev buttons as required based |
{ |
|
btnNext.Enabled |
|
|
on a given BindingManagerBase |
|
|
= (bm.Position < _album.Count - 1); |
|
|
object. |
btnPrev.Enabled = (bm.Position > 0); |
|
|
} |
|
|
|
2 |
Add a Click event handler for the |
private void btnNext_Click |
|
Next button in the Photo tab page |
(object sender, System.EventArgs e) |
|
control of the MainForm window. |
{ |
|
|
|
|
|
|
3 |
Retrieve the BindingManagerBase |
BindingManagerBase bm |
|
object associated with the _album |
= BindingContext[_album]; |
|
data source. |
|
|
|
|
4 |
If the object was retrieved and the |
if ((bm != null) |
|
Position is not at the maximum |
&& (bm.Position < bm.Count - 1)) |
|
value, increment the current position. |
{ |
|
bm.Position ++; |
|
|
|
|
|
|
} |
|
|
|
5 |
Call the EnablePhotoButtons |
EnablePhotoButtons(bm); |
|
method at the end of this handler. |
} |
|
|
|
6 |
Handle the Click event for the Prev |
private void btnPrev_Click |
|
button in a similar fashion. |
(object sender, System.EventArgs e) |
|
|
{ |
|
|
BindingManagerBase bm |
|
|
= BindingContext[_album]; |
|
|
if ((bm != null) && (bm.Position > 0)) |
|
|
bm.Position --; |
|
|
EnablePhotoButtons(bm); |
|
|
} |
|
|
|
This change allows the user to move forward and backward within the selected album. The controls automatically update whenever the Position property is altered. If you compile and run the current code, you will find that the controls still do not update properly when the selected album changes. For this we will need some additional code.
If you look back at .NET Table 17.7 on the BindingManagerBase class, you will see that there is no method to update, or refresh, the controls bound to the associated data source. This is because some binding managers, notably the PropertyManager, have no need for this functionality. The refresh behavior is only required when a data source contains multiple instances. In this case, the binding manager is a CurrencyManager class instance. A summary of this class appears in .NET Table 17.8.
596 |
CHAPTER 17 DATA BINDING |