Click here to Skip to main content
15,881,600 members
Articles / Programming Languages / C#
Tip/Trick

Extension Method to make a control visible in a complex hierarchy

Rate me:
Please Sign up or sign in to vote.
0.00/5 (No votes)
25 Dec 2011CPOL1 min read 21.5K   4   3
Set visibility in complex (or composite) form.

This tip is compliment to the tip at: Extension method to determine if control is visible in complex hierarchy[^].


Consider the scenario where you have multiple nested tabcontrols:


TabControlMain
  TabPageMainOne
    TabControlSubOne
      TabPageSubOne
      TabPageSubTwo
           MyControl
  TabPageMainTwo
    TabControlMoreSubs
      TabPageMoreSubsOne
      TabPageMoreSubsTwo

The common (naive) approach to make MyControl visible on screen is cumbersome and error prone:


C#
// Make my MyControl visible
TabControlSubOne.ActivePage = TabPageSubOne;
TabControlMain.ActivePage = TabPageMainOne;

This kind of works, until the screen is turned into a usercontrol and placed on a third TabControl. Now there is another control to consider, but your code was not designed to do so. This is a common scenario in dynamically composed screens.


Another problem with this method occurs within the screen itself and has to do with maintainability. What happens if we redesign the screen and decide that MyControl should be moved to TabPageMoreSubsTwo? Now the code does not actually show the control, but, because there is a huge 'disconnect' between what we are trying to do and how we are doing it, we might not discover the problem until late.


As stated, the big problem here is the huge difference between what we are trying to do and how we are doing it. What we really need is a method that follows the Parent-hierarchy up to the Form and 'fix' all TabControls (or equivalent) to make the control visible. That is what this extension does.


Usage:


C#
// Make MyControl visible
MyControl.TabSwitchToControl();

This extension method has a nice benefit that we abstract away the 'how', and only the 'what' of the source code remains. +1 For readability.


C#
public static void LogError(this Exception ex)
{
  //TODO: use your prefered error logging mechanism
}

/// <summary>
/// Tries to make your control visible by setting the
/// 'active tab' property (or equivalent) of all tabcontrols
/// (or other container controls) in your form hierarchy. 
/// The method does this in the same order as a user would have to, when using the interface.
/// Supports: TabControl, UltraTabPageControl, UltraExplorerBarContainerControl.
/// </summary>
/// <param name="subjec">The subject.<</param>
/// <param name="shouldActivateControl">True if the control should be activated/selected.</param>
/// <returns>true if subject is assigned, otherwise false.</returns>
public static bool TabSwitchToControl(this Control subject, bool shouldActivateControl = false)
{
    bool result = true;
    if (subject == null)
    {
        result = false;
    }
    else
    {
        List<control> tabSwitches = new List<control>();
        #region Build a list of tabswitched to perform to make the control visible

        var testSubject = subject;
        while (testSubject != null)
        {
            var asTabPage = (testSubject as TabPage);
            if (asTabPage != null)
            {
                var asTabControl = asTabPage.Parent as TabControl;
                if (asTabControl != null)
                {
                    tabSwitches.Insert(0, testSubject);
                    testSubject = asTabControl;
                }
            }
            else
            {
                var asUltraPage = testSubject as UltraTabPageControl;
                if (asUltraPage != null)
                {
                    tabSwitches.Insert(0, testSubject);
                    testSubject = asUltraPage.TabControl;
                }
                else
                {
                    var asGroupContainer = testSubject as UltraExplorerBarContainerControl;
                    if (asGroupContainer != null)
                    {
                        tabSwitches.Insert(0, testSubject);
                        testSubject = asGroupContainer.Parent;
                    }
                }
            }
            // jump up one parent in the hierarchy until the top control is reached.
            if (testSubject != null)
            {
                testSubject = testSubject.Parent;
            }
        }
        #endregion

        //apply the tabswitches in the same order as a user would.
        foreach (Control control in tabSwitches)
        {
            try
            {
                var page = control as UltraTabPageControl;
                if (page != null)
                {
                    page.TabControl.SelectedTab = page.Tab;
                }
                else
                {
                    var asTabPage = control as TabPage;
                    if (asTabPage != null)
                    {
                        var tabControl = asTabPage.Parent as TabControl;
                        tabControl.SelectedTab = asTabPage;
                    }
                    else
                    {
                        var asExplorerContainer =  control as UltraExplorerBarContainerControl;
                        if (asExplorerContainer != null)
                        {
                            var explorerBar = (control.Parent as UltraExplorerBar);
                            var explorerGroup = explorerBar.Groups[control.Name];
                            if (explorerBar.SelectedGroup != explorerGroup)
                            {
                                explorerBar.SelectedGroup = explorerGroup;
                            }
                        }
                    }
                }
            }
            catch (Exception exp)
            {
                // Catch exceptions to prevent application termination because of 
                // a bad event handler. For example a refresh of a control failed 
                // because the internet connection was dropped.
                exp.LogError();
                result = false;
            }
        }
        if (shouldActivateControl)
        {
            subject.Select(); 
        }
    }
    return result;
}


(Edit: Fixed some typos)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
Netherlands Netherlands
Doing that 'computer thing' ever since the C64.

Sometimes I feel that being a programmer is much like being a doctor: You just have to know everything and if you don't, something dies.

Either being an application or a patient.

Oddly enough, more people care about the death of their application, than the massacre of people...

Comments and Discussions

 
GeneralRe: Simple solution - ignore the warning. Pin
#realJSOP27-Dec-11 1:18
mve#realJSOP27-Dec-11 1:18 
GeneralYou should remove this and update the original tip, not crea... Pin
fjdiewornncalwe1-Dec-11 10:37
professionalfjdiewornncalwe1-Dec-11 10:37 
GeneralRe: The website already warned me that this tip was 'very long',... Pin
Kabwla.Phone2-Dec-11 4:43
Kabwla.Phone2-Dec-11 4:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.