|
-
Aug 11th, 2010, 05:41 PM
#1
Keeping track of 'Active' tabpage with multiple TabControls
Hi,
I am building a sort of 'lightweight' Visual Studio, and I'm trying to implement the feature where you can drag tabs to different 'tab groups', viewing multiple tabs side by side.
I got nearly everything working, I show a ContextMenuStrip when you rightclick the tab headers, with the option of creating a new (horizontal or vertical) Tab Group. When that happens, a new TabControl is added dynamically and the selected tab is moved there. You can drag the tabs around inside a TabControl and even from one to another.

The problem now is keeping track of the 'active' tab. Since I have multiple TabControls (not just two, there can be as many as you want theoretically), their SelectedTab properties are basically useless. How am I to determine which TabControl the user is currently working in? Obviously I will always have multiple selected tabs, but only one active tab, in which the user is currently typing, editing, whatever.
I need to know the active tab for obvious reasons: many menu and toolbar items act on the active tab for example.
A short explanation of my controls:
I have one TabGroupContainer control, which inherits UserControl.
I have a TabGroup control, which inherits TabControl.
I have a Tab control, which inherits TabPage.
The TabGroupContainer holds a collection of TabGroups (to which I dynamically add/remove TabGroups when required).
Now I want the TabGroupContainer control to have the ActiveTab property which returns the one and only active tab (out of possibly many selected tabs).
The only logical way is to keep track of the tab that was selected last, for every TabGroup.
At the moment, I am doing this:
- In the TabGroup (TabControl) class, I shadow the SelectedTab property (and return a Tab instead of a TabPage). More importantly, in the property setter, I raise a SelectedTabChanged event:
vb.net Code:
Public Shadows Property SelectedTab As Tab
Get
Return DirectCast(MyBase.SelectedTab, Tab)
End Get
Set(ByVal value As Tab)
If MyBase.SelectedTab IsNot value Then
MyBase.SelectedTab = value
Me.OnSelectedTabChanged(EventArgs.Empty) 'raises event
End If
End Set
End Property
- In the TabGroupContainer, when a new TabGroup is added, I use AddHandler twice to attach both the SelectedTabChanged and SelectedIndexChanged events to one method:
vb.net Code:
Public Function AddGroup() As TabGroup
Dim g As New TabGroup(Me, Me.TabPageType)
AddHandler g.SelectedIndexChanged, AddressOf TabGroup_SelectedTabPageChanged
AddHandler g.SelectedTabChanged, AddressOf TabGroup_SelectedTabPageChanged
Me.TabGroups.Add(g)
Me.LayoutGroups()
Return g
End Function
Private Sub TabGroup_SelectedTabPageChanged(ByVal sender As Object, ByVal e As EventArgs)
Dim g = DirectCast(sender, TabGroup)
If g.SelectedTab IsNot Nothing Then Me.ActiveTab = DirectCast(g.SelectedTab, Tab)
End Sub
So this is where I set the ActiveTab property.
- In the ActiveTab property setter, I raise a custom ActiveTabChanged event, which I handle in the main form to update the form title.
Now, this seems to work as long as there are multiple tabs in a TabGroup. I can select different tabs, and even if there are multiple TabGroups, the active tab is always correct.
However, as soon as there is a TabGroup with just one Tab in it, then I cannot seem to make that tab active. I cannot seem to select it whatever I do. I can click on the tab header, but that doesn't seem to fire the SelectedIndexChanged event (and it shouldn't because there is only one tab, hence the selected index did not change), so my active tab isn't changed.
When I click in the text editor the selected tab isn't changed either.
This last problem can be overcome by a somewhat 'dirty' method: enter the Enter event of the text editor, and set the SelectedTab of the parent TabGroup to the current tab.
So, in the Tab class (which contains the text editor), I do this:
vb.net Code:
Private Sub TextEditor_Enter(ByVal sender As Object, ByVal e As EventArgs)
Dim g = DirectCast(Me.Parent, TabGroupLibrary.TabGroup)
g.SelectedTab = Me
End Sub
However, it still doesn't work. I soon figured out why: I am checking that the previously SelectedTab is not the same as the new value in the property setter of the (shadowed) SelectedTab property. I don't raise the event when they were the same, and in this case they were the same (as there is only one tab in the TabGroup!).
So, I took that check out, and now it seems to work when I click in the text editor.
So one problem remains: the active tab is not changed when you click on the tab header (and not on the text editor). I am clueless as to how I should handle this... I am once again sure there is a simple fix, but I cannot see it. I can click the tab header, and I'm sure behind the hood it responds to this click, but it never raises it SelectedIndexChanged event because the index didn't change but was set to the same value it already had.
I cannot override the SelectedIndex property (so I could skip this check and raise the event anyway even if the value didn't change), and the OnSelectedIndexChanged method is not called, so I cannot use that either...
Help?
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|