20
Debug.WriteLine(ucFollow.Visible);
ucFollow.Visible = true;
Debug.WriteLine(ucFollow.Visible);

ucFollow is a custom UserControl, nothing fancy. The above code prints out:

False
False

Worst part is, this does toggle the actual visibility of the UserControl (i.e. ucFollow does appear once this code is called), but it seems somehow that the Visible property isn't ... well, visible on the backend, and doesn't reflect the change, even though the UI itself does.

I don't even know where to begin troubleshooting this. Does anyone have any ideas as to what could remotely cause this kind of craziness?

Edit: This is with a standard C# WinForm in Visual Studio 2010.

sichinumi
  • 1,835
  • 3
  • 21
  • 40
  • Is this WinForms, ASP.NET, something else? – Michael Liu Jun 22 '12 at 17:24
  • WinForms, sorry, should've specified – sichinumi Jun 22 '12 at 17:24
  • 19
    Well if you broke C# I'm afriad you're going to have to fix it. – Jay Riggs Jun 22 '12 at 17:25
  • What thread are you executing that statement on? – David Yaw Jun 22 '12 at 17:25
  • I would start with using a debugger and stepping into the `Visible` property. Then, if this is not possible, I would register a [`VisibleChanged`](http://msdn.microsoft.com/en-us/library/system.windows.forms.control.visiblechanged.aspx) event handler and set a breakpoint inside and inspect the call stack. – Uwe Keim Jun 22 '12 at 17:25
  • @DavidYaw - This is executed on a separate thread created by an EventHandler. It's located in a function called FormBeforeCall(), which is called using: this.UIThread(() => FormBeforeCall()); – sichinumi Jun 22 '12 at 17:26
  • 2
    There could be many reasons to see this kind of behavior, I wouldn't jump straight to a c# bug conclusion. Please provide a simple reproducible example. – asawyer Jun 22 '12 at 17:26
  • @UweKeim - When I view the Visible property with the debugger, I get the same behavior - Visible is false both before and after that line of code. – sichinumi Jun 22 '12 at 17:27
  • @asawyer - That was a bit tongue-in-cheek, it's probably something I'm doing wrong but I figured we could use a bit of levity on a Friday afternoon. ;) – sichinumi Jun 22 '12 at 17:28
  • @TheDramaLlama Sure, but put yourself in the place of another developer with similar problem in the future, how could they find the information here to help them with a title like that? :) – asawyer Jun 22 '12 at 17:29
  • 1
    Is there a control hierarchy in play? Assigning visible to true doesn't necessarily indicate that the control is visible if it is contained by a parent that isn't visible. – Gabriel Isenberg Jun 22 '12 at 17:25
  • Not that I know of; the ucFollow control is just placed like any other control smack dab in a Form. – sichinumi Jun 22 '12 at 17:29
  • @asawyer Heh, true, good point. :) – sichinumi Jun 22 '12 at 17:30
  • 1
    @TheDramaLlama We will of course need a reproducible example though. We don't have your code base and can only make guesses. – asawyer Jun 22 '12 at 17:31
  • 1
    Is the form visible when you run this code (ie is this code running in the Form.Load event?). If the control isnt physically visible, it will return false until it is. – SwDevMan81 Jun 22 '12 at 17:36
  • @SwDevMan81 - Stole my thunder! I'm about to post the solution below. :) – sichinumi Jun 22 '12 at 17:40

3 Answers3

37

I didn't break C#! :)

Turns out the culprit was the Form.Visible property. Before Form.Visible is set to true, any and all controls on the form will be invisible (Visible = false) no matter what.

However, you can still set Visible properties - they just won't take effect until the Form.Visible property is set to true.

In other words, when I called ucFollow.Visible = true, my program was indeed registering it - however, at that point in the code, ucFollow's parent Form.Visible was still false. Therefore, both the Debugger and my print statements recognized, "Hey, this control's parent form is still not visible, so this control is not visible. Period."

As soon as the form was made visible, all the changes took effect and everything worked great.

Moral of the story: Don't rely on the Visibility properties of your controls unless the form containing them is already visible and running.

sichinumi
  • 1,835
  • 3
  • 21
  • 40
  • 6
    If you'd like to find out if the control *would be* visible (if the parent control was visible), you can see my question [here](http://stackoverflow.com/questions/5980343/how-do-i-determine-visibility-of-a-control) for the solution – SwDevMan81 Jun 22 '12 at 17:57
  • you can mark this as an answer, its perfectly ok to do so. Another wierd and wonderful behaviour of controls visibility (in design mode) is when you have a UserControl that you dont declare in the InitializeComponent().. (for what ever reason)... if you open the form the Control isn't shown nor is it listed in the Properties dropdownlist of controls. – Jeremy Thompson Jun 23 '12 at 05:56
9

the culprit is that controls Visible property is actually a property ( with get; set;) and the set will assign to internal m_Visible member but the get will look through all parent controls and will only return true if all of them have m_Visible == true

anonymous
  • 91
  • 1
  • 1
4

This is the danger of assuming properties and fields are the same thing. They are of course very similar conceptually (that's the point) but they are emphatically not that same mechanically. Have a look at what ucFollow.Visible = true actually does:

protected virtual void SetVisibleCore(bool value)
{
    try
    {
        HandleCollector.SuspendCollect();
        if (this.GetVisibleCore() != value)
        {
            if (!value)
            {
                this.SelectNextIfFocused();
            }
            bool flag = false;
            if (this.GetTopLevel())
            {
                if (this.IsHandleCreated || value)
                {
                    SafeNativeMethods.ShowWindow(new HandleRef(this, this.Handle), value ? this.ShowParams : 0);
                }
            }
            else
            {
                if (this.IsHandleCreated || (value && this.parent != null && this.parent.Created))
                {
                    this.SetState(2, value);
                    flag = true;
                    try
                    {
                        if (value)
                        {
                            this.CreateControl();
                        }
                        SafeNativeMethods.SetWindowPos(new HandleRef(this.window, this.Handle), NativeMethods.NullHandleRef, 0, 0, 0, 0, 23 | (value ? 64 : 128));
                    }
                    catch
                    {
                        this.SetState(2, !value);
                        throw;
                    }
                }
            }
            if (this.GetVisibleCore() != value)
            {
                this.SetState(2, value);
                flag = true;
            }
            if (flag)
            {
                using (new LayoutTransaction(this.parent, this, PropertyNames.Visible))
                {
                    this.OnVisibleChanged(EventArgs.Empty);
                }
            }
            this.UpdateRoot();
        }
        else
        {
            if (this.GetState(2) || value || !this.IsHandleCreated || SafeNativeMethods.IsWindowVisible(new HandleRef(this, this.Handle)))
            {
                this.SetState(2, value);
                if (this.IsHandleCreated)
                {
                    SafeNativeMethods.SetWindowPos(new HandleRef(this.window, this.Handle), NativeMethods.NullHandleRef, 0, 0, 0, 0, 23 | (value ? 64 : 128));
                }
            }
        }
    }
    finally
    {
        HandleCollector.ResumeCollect();
    }
}

(Code courtesy of ILSpy.)

Your answer lies somewhere in that tormented maze of logic.

dlev
  • 48,024
  • 5
  • 125
  • 132
  • I have a feeling my solution can be linked with something in the aforementioned maze of logic, but it's a Friday and I can't be bothered to find it. :) – sichinumi Jun 22 '12 at 17:46