YOUR FEEDBACK
Three RIA Platforms Compared: Adobe Flex, Google Web Toolkit, and OpenLaszlo
NN wrote: Yeah you are right GWT is poor man's Flex. After using GWT on two...

SYS-CON.TV
TOP MICROSOFT .NET LINKS


Tips & Tricks for Using Windows Forms Controls:
Protected members offer solutions to seemingly impossible problems

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
List boxes/combo boxes and menus are handled by controls that are not particularly exciting in terms of their display. Figure 1 shows a different kind of list box in which each item is displayed in the font that it names. This list box also features a "Variable Height" check box, which, if checked, causes the items to be drawn with a variable height. Download the source code for this article from below, run the solution, and choose "OwnerDraw" to run this sample. If the Variable Height box is checked, as you click each font you will see each item displayed in a different height.

 

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
The ListBox control has a DrawMode property that specifies how items are drawn. By default Windows handles the task of drawing the list box items. The DrawMode property is by default Normal. The DrawMode property supports three different values based on the DrawMode enumeration.

 

In this example the DrawMode property has been set to OwnerDrawVariable. Note: A multicolumn list box cannot have a variable height.

Handling Events
You need to handle two events, MeasureItem and DrawItem. If you're just drawing items but not manipulating their height, you need not handle the MeasureItem event. Similarly, if you've set the DrawMode property to Owner- DrawFixed, you don't need to handle MeasureItem. Both of these events provide a DrawEventArgs parameter that provides a number of properties and methods, such as Bounds, Graphic Context, Index, and State, which indicate the state of the item. Figure 2 show a partial list of the parameters and methods exposed in the DrawItem event.

 

Drawing Items with GDI+
In the ListBox DrawItem event we will use GDI+ to draw each item to be displayed in the list box. But first an array of available fonts is created in the Sub FillFonts() method. This array is specified as the data source for the list box. The key code, however, is in the ListBox DrawItem event, which causes each font in the array to be drawn in its own font type.

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,
fnt, br, e.Bounds.X, e.Bounds.Y)

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.

 
Figure 3
 
Figure 4

Exposing Protected Members
Much of the functionality of Windows Forms controls is protected; it's only available in the control class and in classes that inherit from the control. But sometimes you will feel tied down by this and will want to use the protected functionality yourself. The way to do it is to inherit from the control and expose the functionality you require. You can create an actual custom control or simply create a class in your project. Experimenting with protected members is one of the most exciting and enriching experiences available to you as a .NET developer. I'm going to give you just a taste of the wealth of protected members out there.

Synchronized Scrolling DataGrids
Let's examine the following scenario in which a customer had two DataGrids on a form. The customer wanted the ability to scroll either DataGrid and have the other scroll automatically too. Both DataGrids were tied to the same data source (see Figure 5).

 

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
Inherits DataGrid
Public Property CurrentRow()
As Integer
Get
Return
Me.VertScrollBar.Value
End Get
Set(ByVal Value As
Integer)
Me.VertScrollBar.Value = Value
End Set
End Property
End Class

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
sender As Object, ByVal e As
System.EventArgs) Handles
DataGrid1.Scroll
DataGrid2.CurrentRow = DataGrid1.CurrentRow
End Sub

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
Integer
Get
Return
Me.VertScrollBar.Value
End Get
Set(ByVal Value As Integer)
Me.GridVScrolled(Me, NewScrollEventArgs(ScrollEventType
.LargeIncrement, Value))
End Set
End Property
End Class

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
Each and every control available with Windows Forms holds a host of hidden gems in its protected members. Explore them when you're stuck with a control problem that seems impossible; most often you will find a solution out there.

Mohammed Arif Hussain wrote: U r Article it is very nice, when i was found u r Article, i feel great, I'm also Programmer, Now i'm VB6 to VB.Net, Please send me if there is any resources about .Net. Please mail me
read & respond »
MICROSOFT .NET LATEST STORIES
Peer Networking Series - A Closer Look at PNRP vs. Bonjour/ZeroConf
It seems as though whenever I bring up PNRP and its benefits, I am immediately inundated with a list of questions or comments indicating that Microsoft is re-inventing the wheel and that PNRP has already been implemented before in the form of ZeroConf and, more specifically, Apple's im
Microsoft, Unisys, Yahoo and Vista
Microsoft, which spent $6 billion on aQuantive and was chasing Yahoo for its ads before it came to a dead stop, has been supporting - as in helping write - legislation in New York and Connecticut that would regulate the data that companies like Yahoo and Google collect for targeted adv
AJAX World - Xceed Launches Microsoft Silverlight 2 Control
Xceed launched Xceed Upload for Silverlight, the commercial offering in support of Microsoft's promising new Silverlight technology. The product is available now for purchase or as a fully functional 45-day trial on Xceed's website. Xceed Upload for Silverlight lets developers add uplo
Microsoft To Keynote 4th International Virtualization Conference & Expo
Mike Neil is general manager for virtualization strategy in the Windows Server Division at Microsoft. Mike is focused on the delivery of the Windows virtualization technology, including Windows Server 2008 Hyper-V, Microsoft Hyper-V Server and Virtual PC 2007. Mike also directs the tec
Microsoft Virtualization Takes Management Cross-Platform
Microsoft is making System Center, its central management scheme, natively manage Linux, Unix and VMware virtual servers. The widgetry has always been a Windows-only affair, but now there are betas available showing off Microsoft's cross-platform prowess, important to Microsoft's place
SUBSCRIBE TO THE WORLD'S MOST POWERFUL NEWSLETTERS
SUBSCRIBE TO OUR RSS FEEDS & GET YOUR SYS-CON NEWS LIVE!
Click to Add our RSS Feeds to the Service of Your Choice:
Google Reader or Homepage Add to My Yahoo! Subscribe with Bloglines Subscribe in NewsGator Online
myFeedster Add to My AOL Subscribe in Rojo Add 'Hugg' to Newsburst from CNET News.com Kinja Digest View Additional SYS-CON Feeds
Publish Your Article! Please send it to editorial(at)sys-con.com!

Advertise on this site! Contact advertising(at)sys-con.com! 201 802-3021

SYS-CON FEATURED WHITEPAPERS

ADS BY GOOGLE
BREAKING NEWS FROM THE WIRES
Actium Partners with GraphOn to Web-Enable Financial Management Platform
GraphOn Corporation (OTCBB:GOJO), a leading worldwide developer of application publishi