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

CUSTOMIZE THE COLUMNS TO APPEAR IN THE DATA GRID

 

 

Action

Result

 

 

 

 

 

 

1

Locate the OnLoad method in the

protected override void OnLoad(EventArgs e)

 

MainForm.cs code window.

{

 

 

 

 

 

. . .

 

 

 

 

 

 

2

Create a column style for the

// Table style for PhotoAlbum data source

 

Caption property.

. . .

 

How-to

 

 

// Column styles for PhotoAlbum source

 

Use the DataGridTextBoxCol-

DataGridColumnStyle captionCol

 

umn class and assign the Map-

= new DataGridTextBoxColumn();

 

captionCol.MappingName = "Caption";

 

pingName to match the Caption

 

captionCol.HeaderText = "Caption";

 

property name.

 

 

captionCol.Width = 100;

 

 

 

 

 

 

3

Create column styles for the

DataGridColumnStyle validCol

 

IsImageValid, DateTaken,

= new DataGridBoolColumn();

 

Photographer, and FileName

validCol.MappingName = "IsImageValid";

 

validCol.HeaderText = "Valid?";

 

properties as well.

 

validCol.ReadOnly = true;

 

How-to

 

 

validCol.Width = 30;

 

 

 

 

 

Use the class specified for each

DataGridTextBoxColumn dateCol

 

property in the following table.

= new DataGridTextBoxColumn();

 

 

Column Style Classes

dateCol.MappingName = "DateTaken";

 

 

dateCol.HeaderText = "Date Taken";

 

 

 

 

 

dateCol.Alignment

 

 

Property

Class

 

 

= HorizontalAlignment.Center;

 

 

 

 

 

 

 

IsImageValid

BoolColumn

dateCol.Format = "d";

 

 

DateTaken

TextBoxColumn

dateCol.Width = 80;

 

 

 

 

 

Photographer

TextBoxColumn

DataGridColumnStyle photographerCol

 

 

FileName

TextBoxColumn

= new DataGridTextBoxColumn();

 

 

photographerCol.MappingName ="Photographer";

 

 

 

 

 

photographerCol.HeaderText = "Photographer";

 

 

 

 

 

photographerCol.Width = 100;

 

 

 

 

 

DataGridColumnStyle fileNameCol

 

 

 

 

 

= new DataGridTextBoxColumn();

 

 

 

 

 

fileNameCol.MappingName = "FileName";

 

 

 

 

 

fileNameCol.HeaderText = "Image File Name";

 

 

 

 

 

fileNameCol.ReadOnly = true;

 

 

 

 

 

fileNameCol.Width = 200;

 

 

 

 

 

 

4

Add the new column styles to

// Add the column styles to the table style

 

the GridColumnStyles property

albumStyle.GridColumnStyles.AddRange(

 

of the existing table style object.

new DataGridColumnStyle[] {

 

captionCol,

 

 

 

 

 

 

How-to

 

 

validCol,

 

Use the AddRange method to

dateCol,

 

photographerCol,

 

add all column styles at once.

 

fileNameCol

 

 

 

 

 

});

 

 

 

 

 

// Assign the table style to the data grid

 

 

 

 

 

gridPhotoAlbum.TableStyles.Add(albumStyle);

 

 

 

 

 

}

 

 

 

 

 

 

This adds the new column styles to the existing table style object. When a data source of type PhotoAlbum is displayed, the new styles specify which columns should

578

CHAPTER 17 DATA BINDING

appear and how they should look. For example, the column style based on the IsImageValid property is as follows:

DataGridColumnStyle validCol = new DataGridBoolColumn();

validCol.MappingName = "IsImageValid";

validCol.HeaderText = "Valid?";

validCol.ReadOnly = true;

validCol.Width = 30;

This column will appear as read-only with a width of 30 pixels. The column header is modified to use the string "Valid?" rather than the property name. This column is our only column based on the DataGridBoolColumn class. This class appears as a check box, which is checked only if the corresponding value is true. In fact, the displayed check box is a three-state check box in order to support a null state in addition to true and false.

The remaining column styles are all based on the DataGridTextBoxColumn class. A summary of this class appears in .NET Table 17.4. Of particular note is the date column, which uses the Format property in this class to display the date value as a short date string. The Alignment property from the base class is also assigned for this column in order to center the displayed date.

DataGridTextBoxColumn dateCol = new DataGridTextBoxColumn();

dateCol.MappingName = "DateTaken";

dateCol.HeaderText = "Date Taken";

dataCol.Alignment = HorizontalAlignment.Center;

dateCol.Format = "d";

dateCol.Width = 80;

Compile and run the application to see your code in action. The application should appear as in figure 17.4 at the start of this section.

.NET Table 17.4 DataGridTextBoxColumn class

The DataGridTextBoxColumn class represents a data grid column style for string data. This class hosts, or manages within a cell of the DataGrid control, a TextBox instance to support editing of string values within the table. This class is part of the System.Windows.Forms namespace, and inherits from the DataGridColumnStyle class. See .NET Table 17.3 for a list of members inherited from this class.

 

Format

Gets or sets a string specifying how text should be

 

 

formatted within the cell.

 

FormatInfo

Gets or sets an IFormatProvider interface that is

Public Properties

 

used to interpret the Format setting.

 

TextBox

Gets the TextBox object hosted by this column style.

 

 

This object is an instance of the DataGridTextBox

 

 

class, which is derived from TextBox.

 

 

 

DATA GRID CUSTOMIZATION

579

The DataGridBoolColumn class has an alternate set of properties appropriate for boolean columns. Check out the .NET documentation for detailed information on this class.

TRY IT! Modify the MappingName setting for the table style to use a name other than the "PhotoAlbum" string. Verify that the DataGrid displays the album data in the default format shown in section 17.1.

If you are feeling ambitious, create the AlbumCollection class mentioned earlier in the chapter. This class should derive from the CollectionBase class and encapsulate a set of PhotoAlbum objects. You can copy much of the code from the PhotoAlbum class implementation by modifying the use of Photograph to use PhotoAlbum instead. The default constructor should use the PhotoAlbum.DefaultDir value. You can also add a constructor that accepts a directory name. Modify the MyAlbumData application to use this class to display a collection of PhotoAlbum objects. Create a second DataGridTableStyle object to configure how an AlbumCollection object should look as opposed to our style for the PhotoAlbum object. Add this new style to the TableStyles property for the grid, and verify that the correct table style displays based on the type of data source assigned to the control.

As we mentioned earlier, some of our columns are configured as read-only while some of them can be edited. You can see this in the existing application by clicking on an editable cell and modifying its contents. Unfortunately, changing the contents of a cell has no effect at the moment since we are not saving the modified values in our album file. Saving such changes properly requires the use of the IEditableObject interface, which is our next topic.

17.3EDITABLE OBJECTS

So far we have bound a PhotoAlbum object to our DataGrid control and customized the table and columns that appear in the grid. At the moment, any changes made by the user to the PhotoAlbum object are discarded when the displayed album changes or the application exits. This is not really desirable, so let’s discuss how to properly save changes made to the grid.

There are three areas for discussion here. The first is the way in which data grids support editing of their contents. The second is how to enable such support in the Photograph objects displayed by our table. The third is how to actually save the data into an album file once such editing is possible. We will discuss each topic separately.

17.3.1THE IEDITABLEOBJECT INTERFACE

The editing of rows in a grid is handled by the DataGrid control directly using the discovered properties associated with our PhotoAlbum object. When the user changes a caption, the Caption property is called automatically by the grid to

580

CHAPTER 17 DATA BINDING

Pho-

update the corresponding Photograph object with the new value. Similarly, when the photographer is changed, the Photographer property is called. The control even handles the DateTaken property gracefully so that an invalid date value is never assigned to the object.

The problem is that our updated Photograph objects are never saved in the corresponding album file. A quick and easy solution would be to forcibly save the album whenever a new album is selected. For example, the SelectedIndexChanged event handler could be altered as follows, with the modified lines in bold.

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

{

string albumFile = cmbxAlbum.SelectedItem.ToString();

// Forcibly save previous album – not our approach if (_album != null)

{

_album.Save(); _album.Dispose();

}

_album.Clear(); try

. . .

}

This would ensure that the album is always saved, even if the user does not wish to save the changes. Not the best solution, although it does work. A better solution would only save the album if it has been modified, and give the user an opportunity to elect not to save the changes. In order to do this we must know when a Photograph has been changed, and then use this information when a new album is selected.

Implementing this change requires the IEditableObject interface, summarized in .NET Table 17.5. This interface defines a mechanism for modifying an object in a transactional manner, so that either all changes to an object are made or none of the changes are made. This is especially important in databases, where the fields of a row may be dependent on one another, or in multi-user environments, where different users may wish to update the same object at the same time. For example, in a customer order database, you would not want to modify the shipping method without also updating the shipping costs. The IEditableObject interface is used to ensure that this happens.

As an example, the DataRowView class in the System.Data namespace supports the IEditableObject interface to ensure transactional update to the rows in a database. We are not building a database here, but we would like to update the toAlbum object in a consistent manner. The IEditableObject interface provides a way for us to do this over the course of this section.

EDITABLE OBJECTS

581

.NET Table 17.5 IEditableObject interface

The IEditableObject interface represents an interface for performing transactional operations on an object. This interface is used by various .NET classes such as the Windows Forms DataGrid control to allow an object to track and enforce transactional behavior. This interface is part of the System.ComponentModel namespace.

 

BeginEdit

Initiates an edit operation on an object.

 

CancelEdit

Discards any changes made since the last edit operation

 

 

began, including any new objects added to the list with

Public Methods

 

the IBindingList.AddNew method.

 

 

 

EndEdit

Finalizes an edit operation. Any changes made since the

 

 

last edit operation began are made permanent in the

 

 

object, including any new objects added with the

 

 

IBindingList.AddNew method.

 

 

 

17.3.2SUPPORTING THE IEDITABLEOBJECT INTERFACE

Looking at the Photograph class, there are four modifiable properties. These are the Caption, Photographer, DateTaken, and Notes properties. As a result, these are the properties we need to consider in our IEditableObject implementation. The following table summarizes the implementation of the required methods:

Implementation of IEditableObject methods for the Photograph class

Method

Implementation notes

 

 

BeginEdit

Should record the existing values of the modifiable properties and

 

place the photo in an editing state.

CancelEdit

Should reinstate the recorded values from BeginEdit, and place the

 

photo in a nonediting state.

EndEdit

Should discard the recorded values from BeginEdit, note if the

 

photo has been changed, and place the photo in a nonediting state.

 

 

Our implementation will not be something you would present at a computer science convention. In particular, a Photograph object can be modified without using our edit methods, which kind of defeats the whole purpose of the interface. The code presented here is intended to illustrate the behavior of these methods and indicate how they are used by the DataGrid control.

With this excuse in mind, let’s see how to support the editable object interface for our Photograph class.

582

CHAPTER 17 DATA BINDING

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