Click here to Skip to main content
15,663,341 members
Please Sign up or sign in to vote.
3.67/5 (2 votes)
See more:

Using VB.NET 2008 express edition, I have various tabs in a TabControl. Each tab contains numerous controls. At design time, the Visible property of some of these is set to False so that they are hidden from view on program launch until certain actions are performed, etc. A separate piece of code must identify which ones have a Visible property of False while launching.

Programmatically checking the control.Visible property returns False however, for all controls on a tab that is not currently selected. Yet, when that tab is selected, all controls thereon with a Visible property of True are displayed. I can also assign or read a string to/from the Text property of a text box on a tab that is not selected, which indicates that the properties of controls on a non-selected tab are still 'live'.

How does VB 'know' which controls to display if not through use of the Visible property? I would like to utilise the same logic to know which controls will or will not be visible when their parent tab is selected.

I'm already using the Tag property, which could otherwise be used to mirror the Visible property. Aside from inheriting control classes and adding custom properties, might there be other simple ways of achieving this?

Updated 31-Dec-22 7:57am
Sergey Alexandrovich Kryukov 13-Feb-14 21:22pm    
Why doing so? And why inheriting classes seems not simple enough for you? The whole idea of this part of the question seems a bit weird: what is a "custom property"? Do you think there is any difference between properties defined in a library? or that adding a property is a kind of rocket surgery?

More seriously, this what you cannot do: you cannot "inject" new property to System.Windows.Forms.Control.

Olongdomango 13-Feb-14 22:09pm    
I need to keep track of hidden controls to determine the properties of other controls. I've tried data binding, but this doesn't work on hidden controls. Inheriting classes is ok, but I'm adding new functionality to an existing application and I'd rather not re-create the few hundred controls that would be affected! By 'custom property' I simply mean the creation of new properties in my own Class that would inherit an existing System.Windows.Forms.Control Class. It might be possible to use such properties to mirror the Visible property. I wouldn't be 'injecting' anything.
Sergey Alexandrovich Kryukov 13-Feb-14 22:11pm    
My opinion about rationality of such approach remains the same. Nevertheless, I suggested you the comprehensive solution. Please see my answer.

By the way, you pointed out some real problem: in particular, the event VisibleChanges does not allow to figure out what was the reason for the change of visibility: change by calling control's property or some other control which hides your control. Moreover, the event is not invoked then the control got hidden (say, by changing the active tab). This does not allow you to classify visibility into "logical" and "indirect". My solution fully compensates this lack of functionality.

Olongdomango 14-Feb-14 9:50am    
Yes, and yet the VisibleChanges event can be invoked from another function that sets the Visible property of a control on a non-selected tab to True. The handler however still returns a Visible property of False unless the tab that contains the control is selected. Furthermore, there must be another setting that manages the Visible property to determine if a control should be made visible or remain hidden when its parent tab is selected. It appears though that such a setting is not accessible to the coder.
Sergey Alexandrovich Kryukov 14-Feb-14 10:47am    
That's correct.

Still, I would recommend you to pay more attention for the Solution 2. Architectural solution is always better.


Before answering your question, let me tell you what would be my best advice: develop the technique of programming which does not require what control is visible and what is not. I am serious. To me, relying on such knowledge would indicate poor application design.

And now I'll explain you one of the possible universal solutions. Please see:
using System.Collections.Generic;
using System.Windows.Forms;

// ...

    public partial class MyForm : Form { // this class does not have to be a form
        // ...
        class Visibility {
            internal Visibility(bool isVisible) { this.IsVisible = isVisible; } 
            internal bool IsVisible { get; set; }
        } //class Visibility

        Dictionary<Control, Visibility> visibilityMap = new Dictionary<Control, Visibility>();

        void SetVisibility(Control control, bool isVisible) {
            if (control == null) return;
            Visibility value;
            if (visibilityMap.TryGetValue(control, out value))
                value.IsVisible = isVisible;
                visibilityMap.Add(control, new Visibility(isVisible));
            control.Visible = isVisible;
        } //SetVisibility

        bool IsLogicallyVisible(Control control) {
            Visibility value;
            if (visibilityMap.TryGetValue(control, out value))
                return value.IsVisible;
                return control.Visible;
            // or, better use Debug.Assert requiring control to be
            // in the dictionary
        } //IsLogicallyVisible

    } //class MyForm

I hope my simple idea is clear enough. Now, you should apply some discipline: all visibilities should be set only through SetVisibility. The assertion mentioned above could help to reveal the cases when this rule is broken, or you can ignore such violations. The solution is easy to generalize to be applicable for multiple forms, which should all share the facility shown above.

The solution is more general than you expected: it does not require knowing about tab control (otherwise it would not worth the effort).

That's all. Quite easy. :-)

Share this answer
Olongdomango 14-Feb-14 11:10am    
Thank you for your detailed answer. If discipline is observed, this solution provides a good way of keeping track of the visiibility of all control types and is straight-forward. The only drawback is that it must be applied to every single control, but I simplified this task somewhat by initially using a For loop to call SetVisibility to True for each control in Me.Controls (with recursion for children), and then explicitly hiding specific controls with subsequent calls to SetVisibility. This is still much faster than re-creating controls from scratch.
Sergey Alexandrovich Kryukov 14-Feb-14 11:36am    
This is not a drawback, in terms of number of calls; you simply replace all myControl.IsVisuble = true; (false) with the call to SetVisibility. The better solution would only be injecting a new method as deep as to System.Windows.Forms.Control, which seems impossible — Visible is not a virtual property, and so one...

And you don't really need to initialize all dictionary at once. However, if you want that, you could do it recursively in universal way — do you know the technique?

Olongdomango 14-Feb-14 12:16pm    
Yes, I understand that and I have already applied recursion to universally set all controls as visible initially. This is easier in my case because only around 10% of them must be subsequently hidden on program launch. I never needed to write code to initially make all controls visible before, because this was the default property assigned via the designer.
Sergey Alexandrovich Kryukov 14-Feb-14 12:44pm    
Good luck, call again.
And give you more detail on the alternative solution I mentioned in first paragraph of Solution 1, how to develop UI techniques not relying upon the knowledge of such control states as visibility, Enabled, label text, and the like.

To get the idea, I would suggest you learn and analyze applicability of the following architectural patterns ([^]):

MVVM — Model View View Model,[^],

MVC — Model-View-Controller,[^]),

MVA — Model-View-Adapter,–view–adapter[^],

MVP — Model-View-Presenter,[^].
Pay attention for the motivation of those architectures. If you understand it, you would be able to create better design ideas. At this moment, I'll try to explain why those and many other reasonable thinkable architectures (which could be much simpler for simple applications) would not require you to know and retrieve those control states from UI itself.

The idea is: this is because you have some more reliable and integral source of data: data model, view model and the like. This model serves as the source of knowledge on how the UI state should be changed, but not the other way around. You only need to "read" the UI state when you retrieve the values entered by the user: text in text boxed, check states, selection in the lists and grids. You never "read" such things as visibility. Such data acquisition of control states is consistent, concentrated in one logical unit, often "hidden"/encapsulated behind binding, so it is good for maintenance. In contrast to this integral approach, direct manipulation with controls dissipated in code is nearly impossible to support smoothly. You need to understand that you should thoroughly isolate UI from all other aspects of application.

And, by the way, as you mentioned binding you were trying to use: it is not the magic wand. Without proper UI architecture, binding can turn programming into pure shamanism. Unfortunately, these days, it happens to many naive beginners all the time…

Share this answer
Olongdomango 14-Feb-14 11:16am    
Thank you for the interesting links.
Sergey Alexandrovich Kryukov 14-Feb-14 11:37am    
Will you accept it formally, too? I still think that this would be a better approach...
Olongdomango 14-Feb-14 12:21pm    
My projects are only of a small scale, but I'll examine this approach for future work. Thanks again.
Sergey Alexandrovich Kryukov 14-Feb-14 12:43pm    
You are welcome.
Anyway, "architectural approach" is better even for small-scale project.
Good luck, call again.
If you study the sourcecode of the .NET framework you will find a much better solution than those posted here.

The Control class uses the internal function GetState(STATE_VISIBLE) to determine if a Control has set Visible = true or Visible = false, which is independent of the visibility of any parent control.

So this function must be obtained by reflection. As Reflection is slow I convert the MethodInfo into a Delegate which is lightning fast.

private delegate bool delCtrlGetState(Control i_Ctrl, int s32_Flag);
private static delCtrlGetState mf_CtrlGetState;

static ConstructorOfYourClass()
   MethodInfo i_Method = typeof(Control).GetMethod("GetState", BindingFlags.NonPublic | BindingFlags.Instance);
   mf_CtrlGetState = (delCtrlGetState)Delegate.CreateDelegate(typeof(delCtrlGetState), i_Method);

public static bool IsCtrlVisible(Control i_Ctrl)
	// Line 170
	const int STATE_VISIBLE = 0x00000002;
	return mf_CtrlGetState(i_Ctrl, STATE_VISIBLE);
Share this answer
Graeme_Grant 31-Dec-22 17:02pm    
This was already answered and accepted back in February 2014, 8 years ago! Please stick to current questions where help is needed.
Elmue 4-Jan-23 7:35am    
Graeme_Grant: What a nonsense comment! First: The accepted answer is wrong. Second: Lots of people are sent here from Google still today. So please think at least a tiny bit before posting comments!
Benoit Borremans 15-Mar-23 18:09pm    
At first sight I thought the questions was something like :"does a tab corresponds to a sub form of the current form", and if it is not the case (all controls belong to the main form), then how to simulate such a model by putting all controls in the form and, when a tab is selected, make appear only the controls related to that tab ... maybe I'm mistaken.
Elmue 16-Mar-23 9:09am    
Benoit: You have a completely wrong idea how tab controls work. No control is moved around between forms at all. The main form is not affected by changing a tab. Only the controls in the System.Windows.Forms.TabPage are made visible or invisible.

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

CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900