Browse DevX
Sign up for e-mail newsletters from DevX


The Baker's Dozen: 13 Productivity Tips for the Windows Forms DataGrid : Page 4

New developers often struggle with the .NET DataGrid when trying to replicate grid functionality from other platforms, while more experienced developers lament the deficiencies of the .NET DataGrid to address end user requirements. These tips will help both newbies and proficient developers work with the DataGrid.




Building the Right Environment to Support AI, Machine Learning and Deep Learning

Tip 5: Other Filters
The example form I've provided doesn't explicitly have an example of a custom RowFilter. However, all you need to do is set the RowFilter property for the table's default view to any valid ADO.NET RowFilter Expression. For example, if I wanted to show all deductions that were unapproved with an amount greater than ten thousand dollars, all I need to do in the test form is execute the following:

string cRowFilter; cRowFilter="Amount > 10000 AND Approved = false"; DtDeductions.DefaultView.RowFilter = cRowfilter; oGridCtr.Refresh();

If you want to turn the filter off, just pass an empty string to the RowFilter property. Note that the columns specified in a RowFilter expression can only refer to columns in that DataTable. ADO.NET does not support filter conditions that span multiple related tables.

Tips 6 - 8: Defining a Shortcut Menu to Bookmark a Row from the Binding Manager
I was doing some development testing of a fairly large result set, and had to bounce back and forth between records. I found myself copying ID numbers from the grid to Notepad so that I could paste them back into a search later. Eventually, I thought to myself, "there's gotta be a better way!" Many times, I look to Microsoft Word or Internet Explorer to get some ideas for user interface enhancements, and this was no exception. In the same way that both products have a recent document list and bookmark capability (which you pretty much see in most applications these days, including Visual Studio .NET), I decided to implement bookmark capability.

When a user right-clicks on the grid, a pop-up menu appears with options to bookmark the current row, and also to clear the bookmark list

To set up a bookmark, all you do is call the grid container function SetupBookMark, and pass the column name used in the bookmark display. (Note that only one column name can be passed; that's something I plan to expand very soon.)

To set up a bookmark, all you do is call the grid container function SetupBookMark, and pass the column name used in the bookmark display.


And that's it! This sets up a property in the grid container (cColumnToBookMark) that will be used in a few minutes.

Now, when someone right-clicks, the current deduction ID can be bookmarked. It appears in the bookmark drop-down list in the upper right. When the user navigates to a different area of the result set, and then wants to return back to the ID that was bookmarked, selecting it from the drop-down list returns the user to that ID.

As far as how it's handled in the grid container class...first, you need to define a pop-up menu.

private ContextMenu popUpMenu; private MenuItem MiAddBookMark; private MenuItem MiClearBookMarks;

Next, you need to define an event handler to trap a right-click for the grid:

oGrid.MouseDown += new MouseEventHandler(ccGridMouseDown);

In the handler (ccGridMouseDown), you need to check whether the right mouse button was clicked and if so, show the pop-up menu.

if(e.Button==MouseButtons.Right) { popUpMenu =new ContextMenu(); popUpMenu.MenuItems.Add( "Add To BookMark", new EventHandler(popup)); popUpMenu.MenuItems.Add( "Clear Bookmarks", new EventHandler(popup)); this.ContextMenu = popUpMenu; MiAddBookMark=this.ContextMenu.MenuItems[0]; MiClearBookMarks= this.ContextMenu.MenuItems[0]; }

In the custom event popup, take the sender object, cast it to MenuItem, and examine the text. In this case, you want to do something if the text is Add To Bookmark: call the AddRowToBookMark function. (A nice little enhancement here would be to set up an interface, to avoid relying on menu text.)

The AddRowToBookMark function in the grid Container class calls a method in the Grid class called GetCurrentRow, which returns a DataRow object for the current row position. The function respects the sort order by reading the DataRowView that corresponds to the current Binding Manager position. The Binding Manager is defined as a custom grid property, and is defined when the data source is first set.

this.bMgr = this.BindingContext[this.DataSource, this.DataMember]; ... return ((DataRowView)this.bMgr.Current).Row;

I'll talk a little more about the Binding Manager at the end of this section.

So AddRowToBookMark takes the current row returned from GetCurrentRow, examines the value of the bookmark's Column property (cColumnToBookMark), and then checks to make sure the value hasn't already been bookmarked. If it hasn't, AddRowToBookMark adds the value to a collection, resorts the collection, and the repopulates the bookmark drop-down list.

Finally, RetrieveDataFromBookMark in the grid Container class (ccContainers.ccGridContainer) is called any time the user makes a selection from the drop-down list. This function simply takes the current value from the drop-down list and performs a lookup against the default view for the grid's DataSource.

DataView dv = oGrid.dvGrid; for(int nCtr=0;nCtr<dv.Count;nCtr++) if(dv[nCtr][this.cColumnToBookMark].ToString() == cBookMarkValue) { if(oGrid.bMgr.Position >= 0) oGrid.UnSelect(oGrid.bMgr.Position); oGrid.bMgr.Position = nCtr; oGrid.Select(nCtr); lFound = true; break; }

Because it's possible that a bookmarked entry may not exist in the current default view (perhaps the user refreshed the result set with a different condition or the current filter is such that a bookmark value is no longer part of the current view), the function generates a message indicating that the bookmark value could not be found.

Within your application, any time you want to pull back the current row to examine the contents (say, to get a particular string or dollar value from one of the columns), just call the GetCurrentRow function in ccGridContainer.

I mentioned a few paragraphs above that I'd talk about the Binding Manager. In twenty-five words or less, the Binding Manager maintains synchronization between Windows Form controls and the data bound to those controls. There has been plenty of coverage about the details of the Binding Manager (most recently, Dino Esposito wrote an excellent article about Windows Forms data binding in the September/October 2004 issue of this journal), so I won't repeat it.

The Binding Manager is a class derived from the Binding context of the control. Two common instances where you need to directly use the binding manager are when you need to get/set the row position of a grid, and when you want to raise an event when the row has changed (if the user scrolls to a different row, for instance). Quite often, you'll see the following:

BindingManagerBase bMgr = this.BindingContext[this.DataSource, this.DataMember]; int nPos = bMgr.Position;

The ccGrid class exposes a Binding Manager object as a custom property, to avoid having to repeatedly refer to the binding context:

int nPos = oGrid.bMgr.Position;

Then when you want to set up an event any time the position changes, you can define a custom event (like your own function, RowChange).

oGrid.bMgr.PositionChanged += new System.EventHandler(RowChange);

In RowChange, you could take the current deduction ID from the current row, and perform a query, or anything else you need to do.

private void RowChange(object sender, EventArgs e) { oGrid.GetCurrentRow(); string cID = Dr["DeductId"].ToString(); // now go do something with the ID }

There are other uses for the Binding Manager in a data-driven application. Exposing the Binding Manager as a property simplifies the coding to explore them.

Comment and Contribute






(Maximum characters: 1200). You have 1200 characters left.



Thanks for your registration, follow us on our social networks to keep up-to-date