Link to home
Start Free TrialLog in
Avatar of K Feening
K FeeningFlag for Australia

asked on

vb.net tabpage

Hi Experts

I have a tabcontrol with 2 tabpages on the 2nd tab page I have a listview when there is information in the list view I would
Like the 2nd tabpage text (Heading) color to change from black to red / bold to visually tell the user to go o the 2nd tabpage

You help will be appreciated
ASKER CERTIFIED SOLUTION
Avatar of Karrtik Iyer
Karrtik Iyer
Flag of India image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of K Feening

ASKER

no to prompt the user to go to tab 2

Using Microsoft visual studio 8 and vb.net
And you have a listview object on tab2 , so whenever data is changed in that list view, and if user is not on tab2 (means he is on tab1), then change the tab header of tab 2 to red color, is this correct?
Please check if the below works for you, I have a windows form in VB.NET with 2 tabs, in the 2nd tab there is a listview. And when I launch the app, the selected tab is the 1st tab by default. I have a timer in my form to simulate incoming data on tab 2, after 3 seconds, the timer elapsed is called, and I add the items to list view, and then call TabControl refresh to refresh the header.
To draw the color of tab header in different color, in form load I have to set the Drawmode of tab to OwnerDrawFixed and handle the draw item event of tab control. In this draw item event I check if current tab is 1st tab and if new items have got added in 2nd tab then I draw second header text in Red color. See screenshots below. Also attached is the code below.
User generated imageUser generated image
Public Class Form1
    Private _listviewtimer As New System.Timers.Timer(3000)
    Private _changetabheadercolor As Boolean = False
  
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        TabControl1.DrawMode = DrawMode.OwnerDrawFixed
        _listviewtimer.Enabled = True
        _listviewtimer.AutoReset = True
        AddHandler _listviewtimer.Elapsed, AddressOf TimerElapsed
    End Sub
    Private Sub TimerElapsed(ByVal sender As Object, e As Timers.ElapsedEventArgs)
        If Me.ListView1.InvokeRequired Then
            Me.Invoke(Sub() ListView1.Items.Add("ABC"))
            Me.Invoke(Sub() ListView1.Items.Add("DEF"))
            Me.Invoke(Sub() ListView1.Items.Add("GHI"))
            _changetabheadercolor = True
            Me.Invoke(Sub() TabControl1.Refresh())
            _listviewtimer.Stop()
        End If
    End Sub

    Private Sub TabControl1_DrawItem(sender As Object, e As DrawItemEventArgs) Handles TabControl1.DrawItem

        'Get the first tab and draw it normally
        Dim firstTab As TabPage = TabControl1.TabPages(0)

        'Get the area of the header of this TabPage
        Dim HeaderRect1 As Rectangle = TabControl1.GetTabRect(0)

        '  Create two Brushes to paint the Text
        Dim BlackTextBrush As New SolidBrush(Color.Black)
        Dim RedTextBrush As New SolidBrush(Color.Red)

        'Set the Alignment of the Text
        Dim sf As New StringFormat()
        sf.Alignment = StringAlignment.Center
        sf.LineAlignment = StringAlignment.Center
        e.Graphics.DrawString(firstTab.Text, e.Font, BlackTextBrush, HeaderRect1, sf)

        Dim secondtab As TabPage = TabControl1.TabPages(1)

        Dim HeaderRect2 As Rectangle = TabControl1.GetTabRect(1)
        '  Paint the Text using the appropriate Bold and Color setting 
        If _changetabheadercolor And TabControl1.SelectedIndex = 0 Then
            Dim BoldFont As New Font(TabControl1.Font.Name, TabControl1.Font.Size, FontStyle.Bold)
            e.Graphics.DrawString(secondtab.Text, BoldFont, RedTextBrush, HeaderRect2, sf)

        Else
            e.Graphics.DrawString(secondtab.Text, e.Font, BlackTextBrush, HeaderRect2, sf)
        End If

        '  Job done - dispose of the Brushes
        BlackTextBrush.Dispose()
        RedTextBrush.Dispose()
        
    End Sub
End Class

Open in new window

i assume you have a way to figure out that list view on tab 2 has changed, in the above example after adding the data to list view, I explicitly call TabControl.Refresh. Ideally, it would have been good if we have an event to handle in list view which has item added or removed item. To get events for item added or removed we will have to specialize the list view and write our own class, so that we get these events.
You can look at the below article which explains how this works.
http://www.codeproject.com/Articles/4406/An-Observer-Pattern-and-an-Extended-ListView-Event
thanks good code I do have a way to check the list view or if you used a label that changed do you need all the code to just change the color as you showed in the examples tabpage1 / myheader
To change the tab header color the main code is in draw item event and setting property of tab as owner draw fixed in form load. Other things like timer in my code is not needed if you have a way to find out of list view was modified. In draw item I have a boolean flag set to find if list view had been modified that you will have to Set it in your case at appropriate place.
Hi in the code I check mCommentRichText.Text has a value and set warning to true I want to then run the Private Sub TabControl1_DrawItem event to change the color but the Me.Invoke(Sub() TabControl1.Refresh())  the word sub gives error - expression expected
The user on the first Tab scrolls through a table and the data may have a comment or not if it does I want  the 2nd tab to go red as in your display to prompt the user to go to the second tab


 mCommentRichText.Text = reader1.GetString(9)

                            If mCommentRichText.Text IsNot "" Then
                                warning = True
                            Else
                                warning = False
                            End If

                           Me.Invoke(Sub() TabControl1.Refresh())

Open in new window

Hi Kevin which is the version of .NET framework you are using?
Microsoft Visual Studio 2008 Version 9.0.30729.4462 QFE
Microsoft .Net Framework Version 3.5 SP1
Can you try this instead? I think in VS2008 there is no concept of anonymous lambda which I have used in my code earlier.
'Add the below sub to your class
Private sub myTabRefresh()
TabControl1.Refresh()
End Sub
'Change invoke to call like below
me.Invoke(New MethodInvoker(myTabRefresh))

Open in new window

Worked if addressof added to invoker (if not added it gives error - methodinvoker requires an addressof expression) it activates the myTabRefresh event but still not activating the  

Private Sub mDockRecordTabControl_DrawItem(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles mDockRecordTabControl.DrawItem event

If mCommentRichText.Text IsNot "" Then
               warning = True
               Me.Invoke(New MethodInvoker(AddressOf mytabrefresh))
          Else
              warning = False
              Me.Invoke(New MethodInvoker(AddressOf mytabrefresh))
          End If

          Private Sub mytabrefresh()
              TabControl1.Refresh()
         End Sub

          Private Sub TabControl1_DrawItem(ByVal sender As System.Object, ByVal e As System.Windows.Forms.DrawItemEventArgs) Handles mDockRecordTabControl.DrawItem

               Your Code added  here
 
          end sub 

Open in new window

Have you set the draw mode of your tab control like below on form load?
TabControl1.DrawMode = DrawMode.OwnerDrawFixed
Had it turned on but must have turned off when trying to get it to work

Thanks for help all works fine
Excellent support and effort
You are welcome :)