|
|
YOUR FEEDBACK
|
TOP MICROSOFT .NET LINKS Windows Forms Controls
Tips & Tricks for Using Windows Forms Controls:
Protected members offer solutions to seemingly impossible problems
By: Sanjay Shetty
Digg This!
A speaking engagement at Tech-Ed 2003 in India prompted me to put my thoughts on paper for this article illustrating some common tips and tricks to accomplish often-requested Windows Forms controls feature requests. These tips and tricks are based on discussions in various newsgroups online as well as Microsoft presentations. Displaying Controls Your Way
![]() Accomplishing this is an easy, three-step task involving setting the DrawMode property; handling two events, MeasureItem and DrawItem, to override the automatic drawing that Windows provides; and finally using GDI+ to draw the items. Setting the DrawMode Property
![]() In this example the DrawMode property has been set to OwnerDrawVariable. Note: A multicolumn list box cannot have a variable height. Handling Events
![]() Drawing Items with GDI+ Listing 1 shows the code for the ListBox DrawItem event. The DrawItemEventArgs.Graphics property gets the graphics surface on which to draw the item. Depending on the selection state of the item, i.e., whether it's selected or unselected, we draw the item using different brushes. We draw the actual text using the Graphics.DrawString method. We draw the font text in its own font within the bounds as illustrated in the code below. e.Graphics.DrawString(ff.Name, When working with graphics objects you need to make sure all graphics objects are disposed correctly. This is handled in the last section of code in Listing 1. The ListBox MeasureItem event (see Listing 2) is called only if the Variable Height check box is checked. If it is, then the ListBox.DrawMode property is set to DrawMode.OwnerDraw Variable. In the ListBox.MeasureItem event the Graphics.MeasureString method is used to measure the specified string when drawn with the specified Font object. Dim szf As SizeF = e.Graphics.MeasureString(fnt.Name, fnt) The size returned is used to specify the height for the item. However, the space between items is usually not sufficient and the items may appear to be a bit too closely packed. In order to increase the spacing between objects, I've added an extra +4, as shown in the following line of code. e.ItemHeight = CInt(szf.Height + 4) That's about all that's needed to create a ListBox control that draws each item with a different height and in a different font. The example shows some other functions, such as CalcFontStyle, which helps to determine if the specified font has support for Regular, Bold, and Italic styles. Check the source for more details. The same concept can also be applied to menus, as shown in Figure 3. Although there are subtle differences, the basic steps remain the same. Menu items have an OwnerDraw property instead of the DrawMode property used for the ListBox/ComboBox controls. The OwnerDraw property can be set to True or False. As with the ListBox control, you will need to handle the DrawItem and MeasureItem events in your code. Finally, use GDI+ to draw each item. I'm not going to illustrate the code here in detail, but I encourage you to look through the source code provided. Comments at relevant parts of the code highlight the key points. In addition, if you view the Task List in VS.NET 2003, you will see that I have created tasks to help you view significant parts of the code. In Figure 4 the Fill Colors Menu task is highlighted. Doubleclicking each task will take you to the relevant parts of the code. The OwnerDraw form has the code for the ListBox, as well as the Menu.
Exposing Protected Members Synchronized Scrolling DataGrids
![]() A weird request? Perhaps, but it was a challenge and had to be done. But how do you go about it? You need to access the topmost row being displayed, and then sync that with the other DataGrid. Searching in the help file on the DataGrid control revealed that there is no such current topmost row property to hook into. There is a CurrentRow- Index property, but frankly it was of no use. I looked into protected properties in the help file (there are huge numbers of protected properties) and aha! there is a property called VertScrollBar that, according to the help file, gets the vertical scroll bar of the control. I thought I hit the jackpot. Let's see what happens when we try it out. As mentioned earlier, I can create a class in my project and inherit from it. In the following code snippet I've added this code to the end of my form class definition. Public Class MyDataGrid Here I create the MyDataGrid class, which inherits from the DataGrid class. It defines a public property called CurrentRow() and returns the value of VertScrollBar. Then I employ a quick-anddirty trick for using MyDataGrid in the form's code. In the "Windows Form Designer Generated code" section I do a find-and-replace to replace "System.Windows.Forms.Data Grid" with "MyDataGrid". Four instances are replaced. I need to rebuild the project so that the MyDataGrid control is compiled into the assembly and referenced correctly. Hence, when you go to the design view you will see the DataGrids, which otherwise you wouldn't. Note: I have already done the necessary replacements in the source code. This sample assumes the presence of a SQL Server database on the local machine and the presence of the NorthWind sample database. You will need to change the SQLConnection object's ConnectionString to reflect your individual database source. Also Integrated Security is set to SSPI; you may need to change this for your individual environment. The next thing that's needed is to respond to the scroll event. The following code handles that. Private Sub DataGrid1_Scroll(ByVal Hit F5 to run the project and try it out. Choose the SynchScrollDataGrid form and click the "Run" button. Pulling the scroll bar of the first DataGrid down causes the second DataGrid scroll bar to move simultaneously, but the data doesn't scroll. The second DataGrid is still stuck on the first row although its scroll bar is moving. In Figure 6 the DataGrid on the left has been scrolled down and the scroll bar of the second DataGrid has also moved correspondingly but the second DataGrid still shows its first row.
![]() There must be something else we can use to satisfy the customer's request. Going further into the documentation, I find another protected member, the GridVScrolled method, which listens for the vertical scroll bar's scroll event. This method takes a parameter, ScrollEventArgs, which contains the event data and provides data for the Scroll event. So the way to accomplish our goal is to change the setting of the CurrentRow property by using the GridVScrolled method. Here's the CurrentRow property with the changed set statement highlighted: Public Property CurrentRow() As You need to make this change in the code, replacing the line that used the VertScrollBar property. Make the change, hit F5 to run the application, and you're all set. A note of caution: using protected members can be a dangerous thing. They have been marked as protected for a reason: their implementations could change, or they just might disappear down the line. Therefore, you should restrict your use of protected members to areas where you absolutely need it. Conclusion
MICROSOFT .NET LATEST STORIES
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
|
SYS-CON FEATURED WHITEPAPERS MOST READ THIS WEEK BREAKING NEWS FROM THE WIRES
|
|||||||||||||||||||||||||||||||||||||