Additionally, you can set the CellHeader property to an instance of a class that derives from DataGridViewCell , and then that cell type will be used when the header cells are rendered. You can derive your own class from the cell base class and do whatever kind of custom painting, formatting, or setting of styles there that makes sense. As mentioned earlier, when working with a text box column, users can start editing a cell by putting the focus into the cell with the mouse, arrow keys, or by pressing the F2 key when the mouse pointer is in the cell.
If users then start typing characters, the current contents of the cell will be overwritten. When they change the focus to another cell, this completes the editing process. The first thing that happens that you might want to handle is that the CellParsing event fires. Like its CellFormatting counterpart, this event gives you an opportunity to intercept the value that was entered into the cell while in edit mode, either to handle storing that value somewhere yourself or to transform it into some other value before it is stored.
If the cell is data bound, and if the data source supports editing the data objects in the collection, the data will automatically be pushed back into the underlying data source. If the cell is a combo box cell, editing is done by selecting a value in the drop-down list or overtyping the current selection if the cell has its DisplayStyle property set to ComboBox. If the grid is in virtual mode, you will need to handle the CellValuePushed event to grab the value that was entered and do what you need to with it.
When a cell switches into edit mode, an event named EditingControlShowing fires. This event passes an event argument that lets you get a reference to the editing control itself.
The built-in cell types that support editing text box, combo box, and check box cell types create an instance of an editing control that derives from their normal Windows Forms counterparts TextBox , ComboBox , and CheckBox , respectively and display that control as a child control inside a panel inside the cell. If you create a custom cell type that supports editing, then you will want to follow a similar approach. Through the EditingControlShowing event, you can get a reference to the editing control in use and can tap into its event model to respond to edits in real-time.
Keep in mind that the Flag column in the Countries table is actually a byte array containing the bits of the saved image file. The automatic formatting of the image column kicks in here to present the image in the same way that was discussed for a PictureBox control in Chapter 4. The ColumnTypes sample in the download code demonstrates this technique.
One of the most useful values is AllCells. I recommend that this be your default, unless you see a performance hit from using it for large data sets or if you have some cell values that will be very long. This setting ensures that the content of cells never wraps. Additionally, remember to set the FormattingApplied property on the event argument to the CellFormatting event if you are dynamically populating cell values. Otherwise, setting the AutoSizeMode to one of the row values will result in an infinite loop.
As a simple example of using this feature, the following code modifies the code from Listing 6. The Fill mode is very powerful for automatically maximizing the use of the grid real estate, but it can be a little complicated to understand.
Basically, if you set the mode for all columns to Fill , each of the columns will have their width set equally, and the columns will fill the grid boundary with no horizontal scrollbar needed.
If the MinimumWidth property of any column set to Fill mode is wider than the width that was computed using the fill algorithm, then the MinimumWidth value will be used instead, and the other columns just end up being narrower so that they all still fit in the grid without a horizontal scrollbar. If the MinimumWidth values of multiple columns make it so that all columns cannot be displayed, then the columns that cannot be displayed will be set to their minimum width value, and a scrollbar will be displayed.
The default value for minimum width is only 5 pixels, so you will definitely want to set a more sensible MinimumWidth value when working with Fill mode.
The FillWeight can be thought of as the percentage of the remaining available grid width that the individual column will take up compared to other columns that are set to Fill. The following code sets the column width of the CustomerID column to 75 pixels, and then sets the remaining two columns to Fill mode with weights of 10 and 20, respectively. As a result, the remaining two columns occupy 33 percent and 67 percent of the remaining grid width, respectively, after the CustomerID column has taken up its fixed width space.
Scrolling is inevitable when dealing with lots of rows or columns of data. Often when you scroll through data, it is easy to lose the context of what rows or columns you are looking at, especially if that context is based on the values in some other rows or columns.
What you would really want in this situation is to be able to freeze the product name column so that it is always shown and only have the remaining columns scroll. Likewise, there may be situations where you need to present one or more rows at the top of the grid that need to remain in place as you scroll down to additional rows in the grid.
Accomplishing this with the DataGridView control is simple: You just set the Frozen property to true on any row or column to get this behavior. If you are going to freeze a column or row, then you will probably want to provide a visual cue to the user indicating the logical boundary that exists between the frozen item and the non-frozen ones next to it.
The easiest way to do this is to set the DividerWidth property on the column or row to something other than the default. This property is an integer that specifies the number of pixels used to draw the divider between cells of that column or row and the adjacent one to the right or below.
The following code shows a simple example of freezing both a column and a row and setting the divider width:. The DataGridView control supports a very rich experience while working in the Visual Studio designer through a combination of the designer Smart Tags, dialogs, and the Properties window. For starters, if you have defined a data source in your project, you can simply drag a data collection source like a data table onto the form designer and a DataGridView instance will be created with all of its supporting objects.
If you select the grid and display its Smart Tag, as shown in Figure 6. The Choose Data Source drop-down displays a data sources selection window similar to the one described in Chapter 5 for the Properties window. The presented data sources will be tailored to only those that implement the IList interface and thus are suitable for binding to the grid.
The Edit Columns and Add Column links display dialogs that let you define the columns that the grid will contain, shown in figures 6. The Edit Columns dialog lets you add and remove columns, set the order of the columns within the grid, and set all the design-time properties for a defined column in a focused dialog.
The properties shown in the dialog will be tailored based on whether the column is a bound or unbound column, and will expose additional properties based on the column type and cell type. If you define custom column types and include them in your project, they will show up as options for new columns or for configuring columns through this dialog.
The Add Column dialog see Figure 6. If you are adding a data-bound column, you can select from the columns available in the currently selected data source.
You will first have to set the data source to an appropriate collection of data either through the Smart Tag or through the DataSource property in the Properties window.
If you are adding an unbound column, then you just specify the name of the column, the type of the column, and the header text. When you click the Add button, the column is added to the grid, and the dialog remains open so you can quickly define multiple new columns. Configuring the columns through these dialogs writes all the code for you that has been covered earlier in this chapter for defining columns and controlling their runtime behavior. This lets users add a new row to the data collection by typing new values into the cells.
The ability to support this depends on whether the grid is data bound, and, if so, whether the underlying object collection supports adding new items to the collection see the discussion in Chapter 7. The Dock in parent container link is only available if you first drag and drop a grid control onto a form. It does exactly what it says—it simply sets the Dock property to Fill. Setting any of these properties generates appropriate code in the designer-generated partial class for the form in the InitializeComponent method.
Styles are discussed in more detail at the end of this chapter. Column reordering is a slick built-in behavior of the grid that lets users change the display order of columns in the grid at runtime. Because different users of an application often pay more attention to some columns in a grid than others, users commonly request to set the order of the columns displayed in the grid themselves.
While you could support this functionality by programmatically removing columns from the grid and then inserting them back in the new position, that requires a fair amount of tedious code to have to write for a common use case. So the Windows Client team was nice enough to build functionality for this right into the grid control. The way this works is that if the AllowUserToOrderColumns property is set to true and the user clicks and drags on a column header, the grid lets them drag and drop the column to the position where they would like it to display.
The columns to the right of the drop position will move one position to the right, and the columns surrounding the original location of the dragged column will move to be adjacent after the column has been moved.
In this case, the QuantityPerUnit column was clicked on and is being dragged to the left. When you move the cursor to one side of another column, the border between that column and the adjacent one darkens, indicating where the column you are dragging will be placed if you release the mouse button.
The key facets here are that the code in the form Load event handler sets the AllowUserToOrderColumns property to true , allowing the dynamic changing of DisplayIndex for columns through drag-and-drop operations. I then added a CacheDisplayOrder helper method that is called by the Form. Closing event handler, and a SetDisplayOrder helper method that is called when the form loads. It then creates an isolated storage file stream and writes the array to that stream using the XmlSerializer class.
The SetDisplayOrder method does the reverse: it first checks to see if the file exists, and if so, reads the array back in and uses it to set the DisplayIndex on each column in the grid. With the DataGridView , you are already leaps and bounds ahead of the DataGrid for presenting rich data because of the built-in column types that it supports out of the box.
But there are always custom scenarios that you will want to support to display custom columns. Luckily, another thing the DataGridView makes significantly easier is plugging in custom column and cell types. You can handle the CellPainting event and draw directly into the cell itself, and you can achieve pretty much whatever you want with the built-in cell types and some possibly complex drawing code.
But if you want to be able to just plug your column or cell type in a reusable way with the same ease as using the built-in types, then you can derive your own column and cell types instead. The model you should follow for plugging in custom column types matches what you have already seen for the built-in types: You need to create a column type and a corresponding cell type that the column will contain.
You do this by simply inheriting from the base DataGridViewColumn and DataGridViewCell classes, either directly or indirectly, through one of the built-in types.
The best way to explain this in detail is with an example. I want to be able to set a status using a custom-enumerated value, and cells in the column will display a graphic indicating that status based on the enumerated value set on the cell. To do this, I define a StatusColumn class and a StatusCell class I disposed of the built-in type naming convention here of prefixing DataGridView on all the types because the type names get sooooooooooo long. I want these types to let me simply set the value of a cell, either programmatically or through data binding, to one of the values of a custom-enumerated type that I call StatusImage.
StatusImage can take the values Green , Yellow , or Red , and I want the cell to display a custom graphic for each of those based on the value of the cell.
To achieve this, the first step is to define the custom cell type. If you are going to do your own drawing, you can override the protected virtual Paint method from the DataGridViewCell base class. However, if the cell content you want to present is just a variation on one of the built-in cell types, you should consider inheriting from one of them instead.
That is what I did in this case. Because my custom cells are still going to be presenting images, the DataGridViewImageCell type makes a natural base class. I also want the cell value to be able to handle integers as long as they are within the corresponding numeric values of the enumeration, so that I can support the common situation where enumerated types are stored in a database as their corresponding integer values.
The first declaration in this code is the enumeration StatusImage. That is the value type expected by this cell type as its Value property. There is a default status field and corresponding property that lets the default value surface directly.
The constructor also sets the ImageLayout property of the base class to Zoom , so the images are resized to fit the cell with no distortion. The key thing a custom cell type needs to do is either override the Paint method, as mentioned earlier, or override the GetFormattedValue method as the StatusCell class does. This method will be called whenever the cell is rendered and lets you handle transformations from other types to the expected type of the cell.
The way I have chosen to code GetFormattedValue for this example is to first set the value to a default value that will be used if all else fails. The code then checks to see if the current Value property is a StatusImage enumerated type or an integer, and if it is an integer, it casts the value to the enumerated type. Once the status value to be rendered is determined, the GetFormattedValue method uses a switch-case statement to select the appropriate resource name corresponding to the image for that status value.
You embed bitmap resources in the assembly by adding them to the Visual Studio project and setting the Build Action property on the file to Embedded Resource. The code then uses the GetManifestResourceStream method on the Assembly class to extract the bitmap resource out of the assembly, sets the alignment on the CellStyle argument passed into the method, and then returns the constructed image as the object from the method.
The object that you return from this method will be the one that is passed downstream to the Paint method as the formatted value to be rendered. So now you have a custom cell class that could be used in the grid, but you also want to have a custom column class that contains StatusCell s and can be used for setting up the grid and data binding. If you were going to use the custom cell type completely programmatically, you could just construct an instance of the DataGridViewColumn base class and pass in an instance of a StatusCell to the constructor, which sets that as the CellTemplate for the column.
To support that, you need to implement a custom column type that the designer can recognize. The implementation of the StatusColumn class is shown in Listing 6.
You implement a default constructor that passes an instance of your custom cell class to the base class constructor. This sets the CellTemplate property on the base class to that cell type, making it the cell type for any rows that are added to a grid containing your column type.
The next thing the class does is define a public property named DefaultStatus. This lets anyone using this column type to set which of the three StatusImage values should be displayed by default if no value is explicitly set on the grid through data binding or programmatic value setting on a cell.
The setter for this property changes the member variable that keeps track of the current default. The DefaultStatus property on the column is accessed from the StatusCell.
GetFormattedValue method, as described earlier. Another important thing for you to do in your custom column type is to override the Clone method from the base class, and in your override, return a new copy of your column with all of its properties set to the same values as the current column instance.
This method is used by the design column editors to add and edit columns in a grid through the dialogs discussed in Figures 6. The last thing the custom column class does is to override the CellTemplate property. If someone tries to access the CellTemplate , the code gets it from the base class. But if someone tries to change the CellTemplate , the setter checks to see if the type of the cell being set is a StatusCell. If not, it raises an exception, preventing anyone from programmatically setting an inappropriate cell type for this column.
Now that you have defined the custom cell and column types, how can you use them? Well, you can define them as part of any Windows application project type in Visual Studio, but generally when you create something like this, you are doing it so you can reuse it in a variety of applications.
Whenever you want reuse code, you need to put that code into a class library. So if you define a class library project, add the classes just discussed to the class library, along with the images you want to use for displaying status as embedded resources in the project. This creates an assembly that you can then reference from any Windows application that you want to use the column and cell type within.
All you need to do is set a reference to that assembly from the Windows Forms project in which you want to use them, and the custom column types will display in the Add Column dialog, as shown in Figure 6. Within your Windows Forms application, you can programmatically add StatusColumns to a grid, or use the designer to do so. If you add the column through the designer and then look at it in the Edit Columns dialog, you will see that DefaultStatus appears in the property list and is settable as an enumerated property with its allowable values see Figure 6.
With a column of this type added to the grid, you can either populate the grid programmatically with either of the types that the cell is able to handle for values either StatusImage values or integers within the value range of StatusImage , or you can data bind to it with a collection of data that contains those values.
Here is a simple example of setting the values programmatically on a grid containing two columns: a text box column,. Note that you can set the values with either the enumerated value or with an appropriate integer value.
The CustomColumnAndCell sample application in the download code also demonstrates creating a data set and data binding against the status column. You have probably noticed that the DataGridView is much more focused at the cell level that its DataGrid predecessor was. Specifically, users want spread-sheet-like functionality that mimics the interaction model millions of people have become accustomed to with programs like Microsoft Excel and other spreadsheet applications.
Once again, the DataGridView comes to the rescue and makes supporting that model fairly easy. You have already seen some of the cell-level events that let you control what is displayed at the cell level CellFormatting event and that tell you when users interact with a cell by editing the contents EditControlShowing event or simply click on it CellClick event.
There are actually over 30 events raised by the DataGridView that expose interactions and modifications at the cell level that you can subscribe to for providing cell-oriented features. Additionally, there are different selection modes that you can use to change the way the grid highlights cells, columns, or rows when the user clicks in different places in the grid. The DataGridView control supports the selection modes described in Table 6.
Regardless of which of these modes you select, clicking on the upper left header cell the one that is above the row header cells and to the left of the column header cells selects all the cells in the grid.
As an example of a more cell-oriented application, the download code includes an application called SimpleSpread. This application mimics a simple spreadsheet and lets you do summations of the numeric values in a cell. The SimpleSpread sample application is shown in Figure 6. As you can see, the application lets you enter numbers into the cells; then you can select a sequence of cells and press the Sum button in the tool strip control at the top to get it to calculate the sum and place that in the next cell to the right or below the sequence of selections.
As Figure 6. The logic is nowhere near complete to handle all combinations of selections and cell contents, but it gives you a good idea of how to set something like this up. To code this up as shown in Listing 6. As I mentioned, I wanted to support a spreadsheet-like selection model, where you can select individual cells, but that selecting a column or row header would select the entire column or row, respectively.
To do this, I set the SelectionMode for the grid to RowHeaderSelect , turned off sorting for all the columns as I created them and added them to the grid, and then handled the ColumnHeaderMouseClick event to manually select all the cells in a column when the user clicks on a column header.
In this case, I just programmatically added some rows and columns to the grid, set the column headers to be the letters of the alphabet, and turned off sorting on the column by setting the SortMode property to NotSortable. If you were going to support very large spreadsheets, you might need to maintain an in-memory sparse array, and only render the cells as you need them which you could do with virtual mode to avoid the overhead of maintaining a large number of cells, their contents, and their selections if the grid will be sparsely populated.
To get the row numbers to display in the row headers, I handled the RowAdded event and set the header cell value in that handler:. Another selection mode you might want to support is to have hot cells, meaning that the selection of cells changes as you move the mouse around the grid without having to click. To do this, you could just handle the CellMouseEnter and CellMouseLeave events, selecting and deselecting the cell under the mouse in those handlers, respectively.
The last topic I want to cover about the DataGridView is how to handle custom formatting of cells. As mentioned earlier, the grid supports a rich formatting model. The styles in the grid work in a layered model, which lets you set styles at a more macro level, then refine it at a more micro level.
For example, you might set a default cell style that applies to all cells in the grid, but then have one entire column that has a different cell formatting, and have selected cells within that column have yet a different cell formatting. You do this by setting a series of default cell style properties that are exposed on the grid, which you can then refine by setting cell styles at the individual cell level.
As can be seen in Figure 6. Above that layer sits the DataGridViewColumn. DefaultCellStyle property, representing the default styles on a column-by-column or row-by-row basis. The grid also supports an alternating row cell style that is set through the AlternatingRowsDefaultCellStyle property on the grid.
Finally, the top-level layer that will override the settings of any of the lower layers if set is the DataGridViewCell. CellStyle property. You can set these properties programmatically by accessing the appropriate property member on the instance of the grid, column, row, or cell.
All of these properties are of type DataGridViewCellStyle , which exposes properties for setting fonts, colors, alignment, padding, and formatting of values. You can also configure the cell styles through the designer. Whenever you access one of the cell style properties on the grid or a column through the Properties window or Smart Tag property editors in the designer, you will see the CellStyle Builder dialog shown in Figure 6.
Using the property fields in this dialog, you can set fine-grained options for how the cell will display its content, and you can even see what it is going to look like in the Preview pane at the bottom of the dialog. Using these styles, you can achieve some fairly sophisticated grid appearances, as seen in Figure 6.
In this sample, default cell styles were set at the column and row level, and then the filling in of the shape was done through individual cell selection. However, you will still hit some limitations in using cell styles. For example, a natural next step for the grid shown in Figure 6. However, there is really no way to accomplish this just through cell styles, since the border styles available are only 3D effects and are applied at the grid level for entire cells, not for individual sides of a cell.
But, as always, you can almost always accomplish what you need through custom painting or custom cell type definition.
This chapter has covered all the main features of the DataGridView control. It focused a lot on the code involved and what the capabilities were.
The DataGridView control is considerably simpler to use and more flexible and powerful than the DataGrid control from. You will gain a better understanding of what the data-bound controls are looking for when you set up data binding, and how they use what they find. Copy Code. Data Binding with Windows Forms 2. You should also observe that there are four new objects created after the drag-and-drop operation Figure The above code will ensure that when the items in the TitleauthorListBox control are refreshed, the detailed book information of the first title is displayed.
In this article, you have seen how data binding works in Windows Forms 2. There is no need for you to write lots of code in order to perform some common tasks. You just need to know the function of each control such as BindingSource and configure them accordingly. My Subscriber Account Advertise Write. Training Home State of. Staffing Home Looking for Staff? Looking for Work? Contact Us. Dark Kimbie.
Published in:. Filed under: VB. NET WinForms. Figure 1: Adding a new data source to the project. Figure 2: Choosing a dat Select Database as the source of data and click Next. For the server name, enter. Click Test Connection to verify the connection. Figure 3: Specifying the information of the database server. Figure 4: Saving the connection string into app.
Figure 5: Selecting the authors table. Figure 6: Viewing the data source in the Data Sources window. Figure 7: Controls added to the form for databinding. Here are the uses of the various controls: PubsDataSet -A dataset used to represent the tables and relationships in the pubs database.
You can move, or remove ' it, as needed. Figure 8: Testing the application. Figure 9: Changing the controls type to bind. Figure Using Label and TextBox controls for databinding. Figure Testing the application. Sorting While the BindingNavigator control allows you to navigate records by using the VCR-style controls, it is not a practical solution when you have a large number of records.
If you now double-click on the pubsDataSet. Figure Modifying the form. Double-click on Button1 and code the following. Click AuthorsBindingSource. You can also sort the names by either first name or last name Figure Figure Sorting the records by first or last name. Filtering Besides sorting records, you can also filter them. In Form1, add the controls as shown in Figure Figure Adding the new controls. Double-click on Button3 and code the following. Click If TextBox1. Brian Noyes, leading consultant and speaker on.
NET programming, teaches you both the theory and practice of data binding and provides numerous samples ready to run in Visual Studio This product is part of the following series. Click on a series title to see the full list of products in the series. Pearson offers affordable and accessible purchase options to meet the needs of your students.
Connect with us to learn more. Brian Noyes is a software architect, trainer, writer, and speaker with IDesign www. NET architecture and design consulting and training company. He has been developing software systems for more than fifteen years, speaks at many major software conferences around the world, and writes for a variety of software journals and magazines.
We're sorry! We don't recognize your username or password. Please try again. The work is protected by local and international copyright laws and is provided solely for the use of instructors in teaching their courses and assessing student learning. You have successfully signed out and will be required to sign back in should you need to download more resources.
Overview Contents Order Authors Overview. He has a refreshingly clear and crisp delivery as he starts each chapter with a simple tour of each topic, and then leads you into practical concerns for sound practices and extensibility opportunities. Most importantly, as Brian explains approaches to data-binding architecture, patterns of usage, the value of data sets, binding controls and the rest, he always describes how he reaches his recommendations on the topic.
This book is perfect for newcomers to. NET 2.
0コメント