dcsimg
LinkedIn
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Want Tabbed Browsing in Internet Explorer? Build It Yourself with WinForms : Page 3

You can have the best of Firefox without changing browsers. Learn the new controls in WinForms 2.0 and use them to enhance Internet Explorer with a tabbed browsing UI.


advertisement
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 variable—a 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 event—not 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.



Wei-Meng Lee is a Microsoft .NET MVP and co-founder of Active Developer, a training company specializing in .NET and wireless technologies. He is a frequent speaker and author of numerous books on .NET, XML, and wireless technologies.
Email AuthorEmail Author
Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date