Coding the Application
Now that I have all of the controls in place on the form I'm ready to start coding the business logic. First, I'll import the following namespaces:
Imports System.xml
Imports System.Net
These two namespaces contain classes to retrieve XML documents over the Web. In particular, I will use them when downloading content of live bookmarks (RSS feeds). I will also make use of XPath expressions to extract the relevant sections of the document to display.
Declare a global variablea string array to store the list of URLs that the user has typed:
Dim URLsTyped() As String
Define the
ResizeAddressBar() method so that the address ComboBox can be stretched when the form resizes:
Private Sub ResizeAddressBar()
'===Resize the Address combobox when the form is
' resized
Dim size As Size
size.Height = cbbURL.Size.Height
size.Width = Me.Size.Width - btnGo.Size.Width _
- lblAddress.Size.Width - 25
cbbURL.Size = size
End Sub
The
Form1_Resize event will be fired whenever the form resizes:
Private Sub Form1_Resize(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles Me.Resize
'===When the form resizes===
ResizeAddressBar()
End Sub
| Author's Note: Due to a bug in beta 1, the address bar is hidden when the form is first loaded. Maximizing the form will reveal the address bar. |
I will define two methods:
DisplayNewTab() and
DisplayinCurrentTab(). The
DisplayNewTab() method first dynamically creates a new instance of the WebBrowser control and then creates a new tab page within the TabControl control.
The WebBrowser control in WinForms 2.0 is a managed wrapper for the WebBrowser ActiveX control. And thus it is now much easier to use the WebBrowser control than it was in .NET 1.1.
Add the WebBrowser control to the new tab page. Note that when the Web page is being loaded, I set the title of the tab page to "Loading…" (because the title of the document is not yet available at this stage). When the WebBrowser control has finished loading the document, the DocumentTitleChanged event will fire. This is serviced by the WebBrowser_DocumentTitleChanged() method (I will discuss this later). Also note that I have made use of the ToolTipText property of the tab page to store the URL for the page. This is important because you need to be able to display the URL of the current page in the address bar when a tab is selected.
Private Sub DisplayNewTab(ByVal URL As String)
'===Display a page in a new tab page===
'---create a new WebBrowser control instance
Dim wb As New WebBrowser
wb.Dock = System.Windows.Forms.DockStyle.Fill
wb.Location = New System.Drawing.Point(3, 3)
wb.Navigate(URL)
'---update the tab title when the document title
' has finished loading
AddHandler wb.DocumentTitleChanged, AddressOf _
WebBrowser_DocumentTitleChanged
'---create a new tab page and then add to the tab
' control
Dim tp As New TabPage
tp.Text = "Loading..."
tp.ToolTipText = URL
tp.Controls.Add(wb)
TabControl1.TabPages.Add(tp)
'---always display the latest tab
TabControl1.SelectTab(TabControl1.TabCount - 1)
End Sub
The
DisplayinCurrentTab() method displays a Web page in the current selected page. Note that I need to first check if there is a current a tab page selected; if not, I will need to call the
DisplayNewTab() method.
Private Sub DisplayinCurrentTab(ByVal URL As String)
'===Display a page in the current tab page===
If TabControl1.SelectedTab Is Nothing Then
DisplayNewTab(URL)
Exit Sub
End If
Dim wb As WebBrowser = _
TabControl1.SelectedTab.Controls(0)
TabControl1.SelectedTab.Text = "Loading..."
TabControl1.SelectedTab.ToolTipText = URL
wb.Navigate(URL)
'---update the tab title when the document title
' has finished loading
AddHandler wb.DocumentTitleChanged, AddressOf _
WebBrowser_DocumentTitleChanged
End Sub
As mentioned previously, the
WebBrowser_DocumentTitleChanged() method will handle the
DocumentTitleChanged event. One limitation that I faced when using this event is that it passes in a reference from the WebBrowser control that fires the eventnot the tab page. Hence I needed to write code to cycle through all the tab pages to look for the container (i.e. tab page) of this WebBrowser control. Once the particular tab page is located, I will update its page title as well as the address bar and status bar.
Private Sub WebBrowser_DocumentTitleChanged( _
ByVal sender As Object, _
ByVal e As System.EventArgs)
'===Update the title of a tab page when the page
' has finished loading===
'--locate which tab page contains the webbrowser
' control
Dim wb As WebBrowser = CType(sender, WebBrowser)
Dim i As Integer = 0
While Not TabControl1.TabPages(i).Contains(wb)
i += 1
End While
'---Set the tab page title
TabControl1.TabPages(i).Text = wb.DocumentTitle
TabControl1.TabPages(i).ToolTipText = wb.Url
'---Display the URL in the Address combobox and
' Statusbar
cbbURL.Text = wb.Url
StatusStripPanel1.Text = wb.Url
End Sub
There is another
TabControl event that I need to service and that is the
SelectedIndexChanged event. This event is fired whenever a tab page is selected. What I want to do in this event is to display the URL of the currently selected tab page in the address bar and the status bar:
Private Sub TabControl1_SelectedIndexChanged( _
ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles TabControl1.SelectedIndexChanged
'===Update the URL of the selected tab page in
' the Address combobox and Statusbar
Dim tp As TabControl = CType(sender, TabControl)
If tp.SelectedTab IsNot Nothing Then
cbbURL.Text = tp.SelectedTab.ToolTipText
StatusStripPanel1.Text = _
tp.SelectedTab.ToolTipText
End If
End Sub
When the user types in a URL and clicks the Go button, I want to display the Web page in a new tab page and then save the typed URL into the global variable string array:
Private Sub btnGo_Click(ByVal sender As _
System.Object, _
ByVal e As System.EventArgs) _
Handles btnGo.Click
'===GO button===
'---display page in a new tab
DisplayNewTab(cbbURL.Text)
'---save the typed URL into a string array
If URLsTyped Is Nothing Then
ReDim URLsTyped(0)
Else
ReDim Preserve URLsTyped(URLsTyped.Length)
End If
URLsTyped(URLsTyped.Length - 1) = cbbURL.Text
End Sub
Instead of clicking the Go button to load a page, it is much easier for the user to type the URL and then press the Enter key. This can be trapped using the
KeyPress event of the ComboBox control:
Private Sub cbbURL_KeyPress(ByVal sender As Object, _
ByVal e As System.Windows.Forms.KeyPressEventArgs) _
Handles cbbURL.KeyPress
'===When the enter types in the Address
' combobox===
'---bug: this event did not fire when the Enter
' key is pressed
If e.KeyChar = Microsoft.VisualBasic.ChrW(13) _
Then
e.Handled = True
'---display page in a new tab
DisplayNewTab(cbbURL.Text)
'---save the typed URL into a string array
If URLsTyped Is Nothing Then
ReDim URLsTyped(0)
Else
ReDim Preserve _
URLsTyped(URLsTyped.Length)
End If
URLsTyped(URLsTyped.Length - 1) = cbbURL.Text
End If
End Sub
| Author's Note: The KeyPress event did not fire correctly when the Enter key was pressed in Beta 1. This should be fixed with Beta 2, which isn't far off. |
The user can also view a list of URLs that he has typed previously by clicking on the dropdown arrow of the address ComboBox control:
Private Sub cbbURL_DropDown(ByVal sender As Object, _
ByVal e As System.EventArgs) _
Handles cbbURL.DropDown
'===Display in the Address combobox the list===
' of last few web sites URL typed===
If URLsTyped IsNot Nothing Then
cbbURL.Items.Clear()
cbbURL.Items.AddRange(URLsTyped)
End If
End Sub
| Author's Note: For simplicity I did not persist the list of URLs. Using this code, the list will contain only URLs typed by the user in the current run of the application. |
When the user selects the menu Favorites -> Add Live Bookmark..., the application prompts the user to supply the feed URL and then calls the
LoadLiveFavorite() method. This method will load the RSS feed from the supplied URL and then return the title of the feed. The feed title is used to create a file in the "My documents" directory where the URL is written to the content. The file will have a .live extension.
Private Sub AddlivefavoriteToolStripMenuItem_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles _
AddlivefavoriteToolStripMenuItem.Click
'===Add a live favorite to the browser===
Dim RSSfeedURL As String = _
Microsoft.VisualBasic.InputBox( _
"Enter feed", , , , )
Dim RSSTitle As String = _
LoadLiveFavorite(RSSfeedURL)
'---save live favorite to file
Try
Dim filePath As String
filePath = System.IO.Path.Combine( _
My.Computer.FileSystem.SpecialDirectories._
MyDocuments, _
RSSTitle.Replace(":", "") & ".live")
My.Computer.FileSystem.WriteAllText( _
filePath, RSSfeedURL, True)
Catch fileException As Exception
Throw fileException
End Try
End Sub
 | |
| Figure 13. Bookmarks: The "live bookmark" content from an RSS feed is now available to the application. |
The
LoadLiveFavorite() method takes in the feed URL and then makes a request over the Web and loads the return document using an
XmlTextReader object. I then apply XPath expressions to extract the title of the feed as well as the title of the various news items. This information is then used to create menus in the Live Bookmark ToolStrip (see
Figure 13).
Each menu item can be clicked to display its page. Again, I make use of the ToolTipText property of each ToolStripMenuItem control to store its URL and I've also added an event handler to each menu item to service the Click event when the user selects one (see Listing 1).
To load all the live bookmarks subscribed, the user can select the menu item: Favorites -> Load all live bookmarks. This loads all ".live" files from "My documents" onto the live bookmarks bar:
Private Sub _
LoadallLiveBookmarksToolStripMenuItem_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles _
LoadallLiveBookmarksToolStripMenuItem.Click
'===load all live bookmarks from disk===
'---look for all files with .live extension
For Each foundFile As String In _
My.Computer.FileSystem.GetFiles _
(My.Computer.FileSystem. _
SpecialDirectories.MyDocuments, _
True, "*.live")
'---read the content of each file, i.e. the RSS
' Feed URL
Dim filePath As String
Dim RSSURL As String
Try
filePath = System.IO.Path.Combine( _
My.Computer.FileSystem. _
SpecialDirectories.MyDocuments, _
foundFile)
RSSURL = _
My.Computer.FileSystem. _
ReadAllText(filePath)
'---display the live bookmark in the toolbar
LoadLiveFavorite(RSSURL)
Catch fileException As Exception
Throw fileException
End Try
Next
End Sub
When the user selects a menu item in a live bookmark, two behaviors can result: If one page is selected, it will display in the current tab page or if all items are selected, each will display in a series of new tab pages:
Private Sub menu_Click(ByVal sender As _
System.Object, _
ByVal e As System.EventArgs)
'===Display the selected links in a live bookmark
' menu===
Dim menuitem As ToolStripMenuItem = _
CType(sender, ToolStripMenuItem)
'---display all links in tabs
If menuitem.Text = "Open in tabs" Then
If TabControl1.TabPages.Count > 0 Then
TabControl1.TabPages.Clear()
End If
For i As Integer = 0 To _
menuitem.Owner.Items.Count - 3
DisplayNewTab(menuitem.Owner. _
Items(i).ToolTipText)
Next
Else
'---display link in current tab
DisplayinCurrentTab(menuitem.ToolTipText)
End If
End Sub
Finally, when the user right-clicks on a tab page, the context menu appears to allow the user to close the tab:
Private Sub CloseTabToolStripMenuItem_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles CloseTabToolStripMenuItem.Click
'===Close tab context menu to close the current
' tab page===
TabControl1.TabPages.Remove( _
TabControl1.SelectedTab)
End Sub
And there you have it. I began with a simple form using WinForms 2.0's WebBrowser control, among others, and then walked you through each step to write the code that makes these form controls come to life in the form of an enhanced Firefox-like browser. If you've followed along, you should now be able to run your application and try out your own next-generation tabbed browser.
There are still lots areas that you can enhance yourself. I strongly suggest you download the sample code and customize the application for your own use and according to your whims. For me, the ability to use live bookmarks is a good reason for this application to stay on my desktop. And I finally have a Web browser to call my own.