ybase’s DataWindow .NET provides a powerful tool for creating data driven applications with capabilities far beyond the native DataGrid. With it, you can develop flexible, high performance, visually appealing applications with very little coding. The native DataWindow properties, events and methods simplify development.
This article and the downloadable code show you how to create a Windows Form with buttons to Retrieve, Add, Delete, Save, Export, Sort, Filter and Print data. You will create three DataWindow objects using Sybase’s DataWindow Designer and associate each DataWindow with an SQL Server table. Each data entry form accesses a different table. The code behind each button will work for all three data entry forms?without modification?to illustrate the DataWindow’s built-in OOP capabilities. Figure 1 shows the final application.
You will need to download the 60-day evaluation copy of DataWindow .NET from the Sybase site to follow along.
Quick Overview of DataWindows
A DataWindow consists of two components: a DataWindow control and the DataWindow object. The DataWindow control is simple to understand, because it’s much like any other Windows control such as a Button or ListBox. The control comes complete with unique properties and events specific to data access and manipulation. After installing DataWindow .NET, you place the control on the form within Visual Studio by using the “Sybase DataWindow” tab on the toolbox (see Figure 2).
![]() Figure 1. The Sample Application: The figure shows the final application in action with a populated DataWindow. | ? | ![]() Figure 2. Sybase DataWindow Toolbar Tab: Installing DataWindow .NET adds new tools to a Sybase DataWindow tab in the Visual Studio toolbox. |
![]() | |
Figure 3. DataWindow Relationships: The figure shows the relationship between the DataWindow object, the DataWindow control, and a Windows Form. |
In contrast, the DataWindow object is a non-visual component that interacts with the database. You control the database SELECT, INSERT, and UPDATE statements through the DataWindow object’s property settings. The DataWindow object controls the display properties of the data, but you can also dynamically alter them in code. The DataWindow object also controls validation rules, default values, and runtime calculations. You create DataWindow objects using the DataWindow Designer tool, which is (currently) external to Visual Studio, although Sybase is planning a future version that will integrate directly into Visual Studio. After creating each DataWindow, you’ll set two properties so you can interact with the database via the DataWindow object. Behind the scenes, DataWindow objects reside in .pbl files that you must deploy with your applications.
Figure 3 shows the relationship between the object (which contains the SQL), the control (which contains events, properties and methods), and the Windows Form. Create the DataWindow Object
![]() | |
Figure 4. Database Profiles: The Database profile dialog contains a list of connection methods. |
After installing DataWindow .NET, launch the DataWindow Designer from the Windows Start menu. The first step is to identify the database connection to the DataWindow designer, which uses the connection to produce the list of tables and columns to build the visual representation of the DataWindow. I’ve used SQL Server’s pubs database for the example.
From the main menu, select Tools–>Database Profile. You’ll see a list of connection methods. The DataWindow supports native access to many databases, as well as ADO and ODBC access. Select “ODB ODBC” from the list for this example (see Figure 4) and then click “New” to create a new data source.
You’ll see the Database Profile Setup dialog shown in Figure 5. Enter the logical name mypubs in the “Profile Name” field. You’ll use this logical name only within the DataWindow designer.
![]() | |
Figure 5. Database Profile Setup Dialog: The dialog lets you enter connection-specific information to set up a profile. |
Select your ODBC named source by clicking the “Data Source” dropdown and select your new data source. For this example, both the profile name and the data source are called myPubs. With the profile dialog still open, click the “Preview” tab. Click “Test Connection” to verify that you’ve successfully established a connection to your database. Take note of the database connection syntax. You will need to provide that connection string later when you’re building the form. Your connection string should look similar to the following:
ConnectString='DSN=myPubs;UID=;PWD=', DelimitIdentifier='No',CommitOnDisconnect='No'
After successfully testing the connection, you will return to the “Database Profiles” dialog (see Figure 4), where the Connect button will be enabled. Click the Connect button to connect to the database. Now you will be able to select any table or stored procedure within the database when you create the DataWindow object.
Creating a Library Project
You must create a library project to hold the DataWindow objects you create. Select File–>New from the menu. You’ll see a dialog highlighting the project tab. You are creating a new project, so click the project icon in the tab (see Figure 6).
![]() Figure 6. Library Project: Use the Library Project icon to create a new project. | ? | ![]() Figure 7. Saving the Project: The figure shows the new project Save dialog, where you specify a name and location for the new project. |
![]() | |
Figure 8. A Blank Project: When you create a new project, you’ll see two initial files in the project folder in the DataWindow designer. |
Save the project in a folder called myPubsFolder and name the project-library myPubsDataWindow (see Figure 7).
The designer creates two files in the folder. The designer will save all DataWindow objects that you create to the file C:myPubsFoldermyPubsDataWindow.pbl. You will need to deploy this file with the application. The DataWindow designer now shows the blank project (see Figure 8).
Creating a DataWindow Object
Now you are ready to create a DataWindow object that will communicate with the database. Select File–>New from the main menu. Click the DataWindow tab and you will see a list of DataWindow presentation styles (see Figure 9).
![]() Figure 9. DataWindow Presentation Styles: Click the DataWindow tab when creating a new DataWindow displays a list of available presentation styles. | ? | ![]() Figure 10. Selecting a Data Source: The dialog lets you choose from among several data source options. |
You’ll use the tabular DataWindow presentation style first, so click it now. The tabular DataWindow displays data in rows and columns on the page. Note that the DataWindow supports many other presentation styles, including graphs, labels, crosstabs, and grids. Now select the data source for the DataWindow.
Click the icon “SQL SELECT” as the data source (see Figure 10) and then click “Next”. The DataWindow designer presents a list of all the tables in the pubs database because you already connected to the database earlier. Remember, the designer displays the tables of the current database connection. For this application, you’re using only one database, but for multiple-database projects, you’ll need to select the correct database.
Select the authors table and click Open (see Figure 11).
![]() Figure 11. Selecting Tables: After connecting to a database, you can choose the tables to access for your SELECT queries. | ? | ![]() Figure 12. Selecting Columns: After selecting a table, the designer displays a list of columns. |
You now see the list of columns along with several tabs at the bottom (see Figure 12). This is the window from which you select columns and generate the SQL. You can select the Syntax tab at any time to view the generated SQL. Alternatively, if you prefer to type the SQL yourself, you can select Design–>Convert To Syntax from the menu to get an editor that lets you enter the SQL manually. Select the columns in the order you want them to appear on the layout. You could also right-click on the table name and select choose “Select All” from the popup menu.
![]() | |
Figure 13. Sorting Columns: To sort query data, select the columns you want to sort by, and drag them to the right-hand side of the pane. |
In this case, you want to retrieve the data sorted by last name and first name, so select the columns and drag them to the right side of the lower pane (see Figure 13).
Click the syntax tab to view the modified SQL syntax. For this application, you’re going to retrieve all the rows in this table, so you don’t need a WHERE clause. When the SQL syntax looks OK you’ve finished the SQL for this section. I’ll discuss retrieving one row or a set of rows based on a WHERE clause at the end of this discussion.
Using the DataWindow’s Visual Features
![]() | |
Figure 14. Selecting Colors and Borders: From the DataWindow Painter, you can select colors and borders to display. |
From the File menu, select “Return to DataWindow Painter.” Another dialog appears that lets you select colors and borders (see Figure 14).
Click Next to use the default values supplied. A final dialog gives you one last chance to change the settings. Click Finish for now. If you want to modify any portion of the SQL statement at a later time or later date, you can easily do so by returning to the painter.
Modifying the DataWindow Object’s Visual Properties
At this point, you should be looking at the interface designer, which has three main panels (see Figure 15). You can use the visual layout and properties panel to:
- Resize columns, change fonts and rename the header.
- Create controls on the screen.
- Disable the primary key column except for new rows.
- Show a conditional bitmap.
- Change the color of a column.
- Add a footer line to calculate the total number of rows in the DataWindow.
- Set the update properties that will generate a SQL UPDATE statement to the database.
I’ll briefly describe each of these operations in the following sections.
Resizing Columns, Changing Fonts and Renaming Headers
![]() | |
Figure 15. Interface Designer: The designer has three main panels, from which you control the DataWindow layout, change headers, resize columns, and change fonts. |
Click on the header band and the column called au_lname. The column headers take their default names from the column names, but you can change the displayed column names. Using the properties panel, change the text to “Last Name” (see Figure 15).
Click on the Alignment control and set it so the header is left aligned. Alternatively, you can change the text using the toolbar. Go to the header band and shrink the width to one-half the original size. Next, resize and align the column containing the data. Click on the header band and the Last Name. Hold down the CTRL key, and click the object showing au_lname in the detail band. Use the toolbar (see Figure 16) to size both objects to the same width, and then align both to the same left position. Using the right arrow key, move both objects slightly to the right. Use the arrow key on the properties tab and scroll to the right. Change the font to Courier New.
![]() | |
Figure 16. Changing Alignment: Use the Alignment toolbar controls and the arrow keys to align and size objects. |
Create a Control on the Screen
You are going to change the contract column to display a checkbox. This column has two possible values, so a CheckBox is an appropriate control. Scroll to the right of the top panel (in visual layout) and click the object named “Contract” in the detailed band. Use the Properties tab to find the Edit tab. Select CheckBox as the type and fill in the data value on as 1, data value off as 0. You may need to scroll down to see all properties for the checkbox. Scroll through the data view and verify this column is now a CheckBox. Resize the CheckBox appropriately and center it below the header column.
Disable the Primary Key Column Except for New Rows
![]() | |
Figure 17. Disabling Columns: Click on a detail object and the Protect icon to get a Protection dialog where you can enter protection conditions. The code in the figure disables the primary column except for new rows. |
Typically, you want to prevent users from changing the primary key column unless they’re adding a new row. To do so, click on the detail object named au_id. Go back to the General tab (the first tab) on the property pane. Click the red image next to the label “Protect.” Enter the text below (see Figure 17).
if(isRowNew(),0,1)
Show a Conditional Bitmap
Suppose you wanted add a bitmap to appear if a user selects a state that begins with the letter “C.” To do this, you add a calculated column instead of adding a bitmap directly. Both methods work, but computed columns are more powerful and can contain many things?including several columns from the database. For example, you can set the visible property based on a condition if you added a bitmap directly to the form. Use the menu Insert–>Control–>Computed Column to insert a computed column. You could also use the toolbar as shown in figure 18.
![]() | |
Figure 18. Inserting Computed Columns: The “+/=” icon on the toolbar lets you insert a computed column. |
Click just to the right of au_lname in the detail band to place the computed column on the form. Enter the following in the expression dialog. The downloadable code contains the redball.jpg image.
bitmap(if( state like 'C%',"redball.jpg",""))
Unfortunately, the image is extremely pixelated. That’s because the image is really 14 x 9 pixels, so you need to change the size of the computed column. Click the object in the detail band and navigate to the Position tab. Set the width to 14 and the height to 9. The image should appear as expected.
Change the Color of a Column
You can change display colors based on conditions. Here, you’ll set the phone number column value to display in blue if the author has a contract and lives in California. Click on the object phone located in the detail band. Navigate to the Font folder in the Properties window. Click the small red image next to Text Color and enter the following line in the expression dialog.
if(state='CA' and contract =1, rgb(0,255,0),rgb(0,0,0))
Note: You can change the text color without setting a condition by simply selecting the color from the dropdown list.
Add a Header and Footer
![]() | |
Figure 19. Toolbar Convenience: Available toolbar icons let you add a title, page numbers, a date, and underline column headings. |
In the designer, click the header band and slide it down to create another half inch of space. Do the same on the footer band. Now click the first column in the header band (au id) and then choose Edit–>Select–>Select Right to select all the items in the header band. Use the arrow keys or mouse to slide all the labels down. Use the toolbar (or menu) to add a title, page numbers, date and column heading underline (see Figure 19).
The underline tool looks like a straight line. Click on the header line and stretch it to the last column. On the General tab of the Properties window, set the pen width to 3 for the underline. Now add a computed column to the footer. Use the toolbar or the menu Insert–>Control–>Computer Field. Enter the following in the expression box:
"Total Rows: " + String(count( au_id for all ))
Make the column bold using the Properties tab (Font) or the toolbar and resize it until it’s large enough to display the whole message. The footer will appear on each page. As you can see, the DataWindow provides powerful display options.
Rows?Update Properties
![]() | |
Figure 20. Specifying Update Properties: The figure shows the Specify Update Properties dialog, where you specify key columns, how the DataWindow should update changes to key columns, and which columns to update. |
Obviously, one of the most important features of database applications is letting users edit data and save their changes. To do that, you need to tell the DataWindow which columns to update and how to generate the SQL UPDATE statements to save changes.
First, select Rows–>Update Properties from the menu. You’ll see three possible options on the dialog in the “Where Clause for Update/Delete” section: Key Columns, Key and Updateable Columns, and Key and Modified Columns (see Figure 20). Table 1 describes how you can determine which option you should select.
Table 1. Three options for determining which type of WHERE clause a DataWindow should generate.
Option | Description |
Key Columns | The WHERE clause will contain only the primary key, for example:Update authors set fieldlist = value where au_id = ‘123’All changes made by the current user will overwrite any prior changes made by other users. Least used of the three options |
Key and Updateable Columns | The where clause will contain the primary key and all the columns that are updateable on the screen. This option compares all columns to make sure nothing else changed since the retrieve was done, for example:
The update will return an error message if any other user has updated any data since the DataWindow retrieved the primary key Most commonly used option |
Key and Modified Columns | The where clause will contain the primary key and only those columns that changed via the data entry screen. For example this option generates the statement:
(if the only column that changed was contractor and the original value was 1)Useful if your screen displays non-editable columns and one department owns update responsibilities for specific columns within the same table. |
Save the DataWindow object and name it de_authors. To save the DataWindow, use the menu options File–>Save. Name the object de_authors in the Save Template?XHTM dialog (see Figure 21), as well as in the Save DataWindow (see Figure 22) dialog.
![]() Figure 21. The Save Template?XHTML Dialog: Be sure to name your template in this dialog, which you reach from the File–>Save menu. | ? | ![]() Figure 22. The Save DataWindow Dialog: Name your DataWindow in this dialog, which you reach from the File–>Save menu. |
Using Your DataWindow
Now that you’ve created the DataWindow object, you can use it in a Windows application. Create a windows project called FirstDataWindow. I’ve used C# for the sample code, but you could use any .NET language. Save the project in the myPubFolders Folder where you saved the .pbl file containing the authors DataWindow earlier. Use Visual Studio’s Solution Explorer to rename the default form to FirstDataWindow.cs. Resize the form until it’s large enough to hold the buttons shown in Figure 23.
![]() Figure 23. Sample Application Buttons: The figure shows the buttons you should add to create the sample application. | ? | ![]() Figure 24. Sample Form with Named and Anchored Buttons: The figure shows how you should place and anchor the buttons on the sample form. |
Name all button objects according to their visual label, e.g. buttonFilter, buttonAdd, buttonPrint, etc. Set the anchor property to “Bottom, Left” for all buttons.
When you’re done, the form should look like Figure 24.
Adding the Transaction Object
You need to establish a transaction object to connect the application to the database. All databases support the transaction objects and return error codes and status codes via this object. Here’s how to add the non-visual transaction object to the form (note that you could add it entirely through code?typically three to six lines of code depending on the database). Click Toolbox and select the Sybase DataWindow tab (see Figure 2). Click on the Transaction object, and slide it to the form. You won’t see any visual indication, but there is now an additional control on the form. Because the sample application uses ODBC and you configured all the parameters earlier, you need to set only the dbparameter to:
ConnectString='DSN=myPubs;UID=;PWD=', DelimitIdentifier='No',CommitOnDisconnect='No'
The ODBC setting shown uses Windows Authentication. Provide your User ID and password in the ConnectString if you’re using SQL Server authentication. Verify that the setting is correct by clicking the Test Connection link on the properties tab of the transaction (at the very bottom). For this example, you’re setting the transaction object on the Windows Form. Typically, you would set the transaction one time for the entire application. The transaction object is analogous to a .NET DataAdapter?the DataWindow uses it to pass requests to the database and receive information and data from the database.
Adding the DataWindow
Next, add a DataWindow control to the form. Remember, the DataWindow control is generic; you set properties so that the control knows which DataWindow object to use. Select the DataWindow Control from the toolbox and drag it to the form. Visual Studio gives the control a default name of dataWindowControl1. Rename the control to dwc1 and resize it until it takes up most of the screen just above the buttons. Set the following properties:
LibraryList = C:myPubsFoldermypubsDataWindow.pblScrollBars = VerticalAndHorizontalSplitDataWindowObject = de_authorsAnchor = Top, Bottom, Left, Right
Set the library list first. Then follow the button in the dialog to point the library list to the .pbl file you created using the DataWindow designer (see Figure 25).
![]() Figure 25. Library List: Although you only have one library at present, the Library list lets you choose from among available libraries. | ? | ![]() Figure 26. The Sample Form: The figure shows how your form should look after selecting the authors DataWindow library. Note that no data appears on the form yet. |
After identifying the library list file you’ll see all the DataWindows in that pbl library (you’ve created only one so far). Select the authors DataWindow You’ll see the visual data presentation (without data) on the form, which should now look similar to Figure 26.
You won’t be able to view the data until you add a bit of code to connect to the database and run a query.
Retrieving Data
Finally! Some programming! You want to connect to the database when the form opens. Place the following code in the form1_Load function.
// connect to the database using the transaction objecttransaction1.Connect();
Now add two lines to the Retrieve button clicked event:
// tell the DataWindow what transaction to use // and then retrieve the datadwc1.SetTransaction(transaction1);dwc1.Retrieve();
Add one line of code to the close button to close the form:
this.close();
Run the application and click the Retrieve button and you’ll see the data from the authors table. Resize the window and you’ll see that the Page field in the header section automatically recalculates the pages. That page figure is accurate when you print as well.
Printing, Sorting, Filtering, and Exporting
Here’s one of the main features of the DataWindow: It’s a WYSIWYG (What You See Is What You Get) control. When you print, you’ll get exactly what you see on the screen?except that the page numbers will reflect the number of printed pages rather than the number of onscreen pages.
To add the print functionality to buttonPrint_Click, place the following code in the handler. //print to the default printer devicedwc1.Print();That’s it! To test the print feature, run the application and click the Print button. The rptAuthors.pdf file in the downloadable sample code shows the actual printout.
Sorting and filtering share the same concept; you first set the sort or filter condition, then execute the action (sort or filter). If you provide a null string as the condition, users will be able to create their own conditions. Add the following code to the ButtonFilter_Click and ButtonSort_Click event handlers:
// ButtonFilter_Click code String sNull = null; //set the filter (Null let's the user do it) dwc1.SetFilter(sNull); //execute the filter on the local dataset ? // no trip to the server! dwc1.Filter();// ButtonSort_Click code String sNull = null; //set the Sort (Null let's the user do it) dwc1.SetSort(sNull); //execute the sort on the local dataset ? //no trip to the server! dwc1.Sort();
Now run the application, retrieve the data and test the filter. Enter a filter condition such as: phone like ‘4%’. The expression dialog lets you build the condition and won’t let you save incorrect syntax. The Sort dialog lets users drag and drop the columns on which to sort. Note that, for simplicity, the sample code doesn’t include any error handling or error prevention. In a real-world application, you would disable all the buttons until the data retrieval process completes. You could add a function and pass true or false to enable/disable all buttons.
One final flashy capability: The DataWindow can export to Excel, XML, CSV, Text, SQL Insert and PDF. Exporting to PDF requires you to deploy an additional ghostscript DLL, but you can generate a XML file with just a little code. Add the following code to the ButtonExport_Click method.
// save as XML based on FileSaveAsType.Xmldwc1.SaveAs("c:\myPubsFolder\test.xml", Sybase.DataWindow.FileSaveAsType.Xml);
You can view the generated XML file using Internet Explorer or your favorite XML viewer.
Saving Changed Data
You’ve now created a data entry form, but haven’t provided the application with the ability to update the database. The DataWindow won’t save changes until you add a little more code. The following try…catch block commits the data only if the user’s changes are valid. Before saving, the code calls the AcceptText() method, which captures all pending changes if users have not moved the cursor off the last column they changed.
//get all changes pending in the buffer if the user //has not tabbed away from the last column changeddwc1.AcceptText();try{ //try to update dwc1.UpdateData(); //commit the changes transaction1.Commit();}catch (Sybase.DataWindow.DbErrorException ex){ MessageBox.Show(ex.SqlErrorText+"
"+ "Changes Not Saved", "Database Error Encountered");}catch (Exception ex){ MessageBox.Show(ex.ToString(), "Unexpected Error Encountered");}
Adding New Rows
You add new rows to the DataWindow by calling the InsertRow() method. Supply 0 as the argument to add the row at the bottom, or supply a number less than the total number of rows to insert a blank row between existing rows. After inserting the new row, you will probably want to scroll to the row. You could highlight the row, but for now, just let the user click in the row and start entering data. Add the following code to the ButtonAdd_Click method.
//ButtonAdd_Click event://add a row to end (0=add to end)dwc1.InsertRow(0);//get the count of rows and go//to the last row.dwc1.ScrollToRow(dwc1.RowCount);
Deleting Rows
Here’s some quick code to delete a row when a user clicks in a row and then clicks the Delete button. This sample simply displays the deleted row, but ideally, you’d present a warning message with better information before issuing the DeleteRow() method. Remember, the DataWindow doesn’t physically delete the row from the database unless the user clicks Save. Until that point, delete, add, and edit changes occur only in a buffer area. Add the following code to the ButtonDelete_Click method.
// buttonDelete code //delete the current row int nRow; nRow = dwc1.CurrentRow; //make sure the user has made a row active by //selecting one with the mouse if (nRow > 0) { dwc1.DeleteRow(nRow); MessageBox.Show(nRow.ToString(), "Deleted a row"); }
One Finishing Touch?Closing the DataWindow Form
Before letting users close the form, you’ll want to detect whether they have pending changes (inserts, deletes, edits) that have not been saved. The following code checks for unsaved changes, and when found displays a dialog that provides a warning, but still lets users elect to exit without saving changes. Add the following code to the ButtonClose_Click handler.
// ButtonClose_Click int nRows; dwc1.AcceptText(); nRows = dwc1.ModifiedCount + dwc1.DeletedCount; if (nRows > 0) MessageBox.Show("Save your changes or exit " + "via the window menu",nRows.ToString() + " Pending changes not saved"); else this.Close();
Object-Oriented Design and More
For some final thoughts, it’s worth noting that the code you placed on the form is independent of any DataWindow object that you might place on the window. Because the DataWindow separates data access and data interaction from the control, the DataWindow control works with any DataWindow object. To prove this, you’ll modify the FirstDataWindow project by adding code that lets you select the DataWindow object that the control uses. Use the dropdown list at the top to select from three different DataWindows, and then click the Retrieve button. You don’t have to change a single line of code to get all the functionality of the buttons.
Create two new DataWindows using the DataWindow Designer. Create one DataWindow object named de_stores that accesses the stores table. Create another DataWindow object named dw_sales. Now go back to Visual Studio and add a ComboBox control to the form. Name the object comboBox1. Set the Items property to “Collection”. Click the ellipse button, and then enter the following four lines in the string collection editor:
de_authorsde_storesdw_Salesde_titlesauthors
Change the code for the buttonRetrieve control so it dynamically changes the DataWindow object based on the combo box selection.
String sDatawindowObject;sDatawindowObject = comboBox1.Text;if (sDatawindowObject.Length <= 3) // set to de_authors if somehow the user did not // select one of the 3 valid datawindows sDatawindowObject = "de_authors";// tell the datawindow what transation to use along // with the dataobjectdw1.DataWindowObject = sDatawindowObject; //dynamically change the datawindowdw1.SetTransaction(transaction1);dw1.Retrieve();
You'll be surprised at the results.
This article has barely scratched the surface of the DataWindow's capabilities as either a user interface control or as a data access control. You can see the query generated when the DataWindow talks to the database by adding the following code to the DataWindow control. Each call to the database (SELECT, INSERT, DELETE, UPDATE) triggers the SqlPreview event. Select the DataWindow control and click the events list to add this event. You'll see question marks in place of the data unless you change the BindVariable parameter.
//dwc1_SqlPreview code MessageBox.Show(e.SqlSyntax,"SQL Generated");
There's simply not enough space in this article to cover more advanced topics, such as:
- Master-detail windows
- Drilldown capabilities
- DropdownDataWindows
- Validation
- Dynamic controls
- Controlling properties using code
- Datastores (non visual DataWindows)
- Deployment capabilities
DropdownDataWindows are extremely important when a column in one table relies on a column in another table. In essence, you nest one or more DataWindows within a main DataWindow object to achieve master-detail capability. For example, you can achieve the functionality of embedding a ComboBox within a DataGrid column via the DataWindow with no coding. Set the Edit property to DropDownDW and select the DataWindow you want to use as the dropdown. The sample source code contains two DropdownDataWindows attached to the DataWindow de_titlesauthors.
Figure 28 shows the result of clicking one of the dropdown arrows on a DataWindow containing several DropDownDataWindows.
![]() Figure 27. Embedding a DropDown DataWindow in a Column: Embedding a dropdown list in a column requires no code. | ? | ![]() Figure 28. DataWindow with Embedded Dropdowns: The figure shows the result of clicking a dropdown arrow in a DataWindow containing several DropDownDataWindows. |
You've seen the most basic DataWindow capabilities, and it should be clear that you can use the DataWindow control to create a form that accesses any database, lets users issue their own queries and return the data in a grid, complete with sort, filter, print, and export functionality?all in fewer than fifty lines of code.