Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C# ПІДРУЧНИКИ / c# / Manning - Windows.forms.programming.with.c#.pdf
Скачиваний:
108
Добавлен:
12.02.2016
Размер:
14.98 Mб
Скачать

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

Соседние файлы в папке c#