none
Extremely bizar visible behaviour

    Question

  • Hello all,

    I have an application where in a window, on the left there is a tabcontrol, filling 2/3 of the width, and on the left a panel filling the other 1/3.

    When the user browses the tabcontrol, I show a particular panel on the right showing some extra info on the tabpage.

    To do this, I have made several panels with content, placed them on top of each other and I set the visibility of the panels according to the tabpage that is shown. Now, with one panel in particular, I have some strange behaviour with the visibility.

    Let me show you:

    When I first open the tabpage, the panel is shown as:

    When I leave the tabpage, and return to the previous one for the second time, it looks like this:

    Now, because of forum restrictions I can't show you the following, but believe me when I say:

    The third time that I visit the tabpage, the panel shows everything but one label. All the next times I visit the tabpage the panel is shown as it should. This behaviour is allways 100% repeatable.

    Now, this panel, shown above contains a UserControl, and it is in that usercontrol where the labels are placed. (Almost every brown square is a label).

    Now, you wonder, how do you hide it? Well, I listen on the tabcontrol's tabpage changed event and execute the following code:

            private void ShowExtraPanel(TabPage tabPage)
            {
                foreach (var item in _extraPanels)
                {
                    if (item.Key != tabPage)
                    {
                        HideControl(item.Value); 
                    }
                }
    
                if (_extraPanels.ContainsKey(tabPage))
                {
                    ShowControl(_extraPanels[tabPage]);
                }
            }
    
            private void ShowControl(Control control)
            {
                if (!(control is ImpressiveGuiGuide))
                {
                    control.Visible = true;
                    control.BringToFront();
                    control.Refresh();
    
                    foreach (Control item in control.Controls)
                    {
                        ShowControl(item);
                    }
                }
            }
    
            private void HideControl(Control control)
            {
                foreach (Control item in control.Controls)
                {
                    HideControl(item);
                }
    
                control.Visible = false;
            }
    

    As you can see, I hide the controls from in to out, and I show from out to in. I do this because I have a feature that listen's to the Visiblechanged event of some controls, and to make that event fire off good, I need to hide/show the panels this way. (When I would hide the container before hiding the inner label, the label would never fire the visiblechanged event and vice-versa)

    An important sidenote also, after I have set the visible to true, it is true (it's not false) I have tested this by showing a messagebox if the visible property was false after setting to true, no messagebox was ever shown.

    I also want to make clear that, the code that is executed on the visiblechanged event, does not alter the visibility of the control that fired the events. To make you believe it, only the labels on the left side (the ones with orange text) are being listened for the visibilitychanged event, the labels on the right (which have currently no text) are not being tracked for the visibilitychanged event.

    Now, this is getting very long and it's even getting to confuse me! So I hope after reading this you understand what my problem is, what I'm trying to do and if possible comming up with a solution.

    Thanks in advance!

    PS: I target .NET 4 FULL

    Thursday, June 27, 2013 7:52 AM

Answers

  • I'm not sure I understand what you are doing.

    Are you hiding and showing every label?

    Is there a reason that you cannot simply hide the panel which contains them?

    For Each loops like this often result in undesired behaviour and you are better off using a For Next loop instead.

    Pseudo code:

    For int index = 0; index < myPanel.Controls.Count; index++
    {
        change visibility of myPanel.Controls[index]
    }



    Mick Doherty
    http://dotnetrix.co.uk
    http://glassui.codeplex.com

    • Marked as answer by Denny007 Wednesday, July 10, 2013 6:28 AM
    Tuesday, July 09, 2013 5:35 PM

All replies

  • Hi Denny007,

    Sorry I might be rude but I don't quite understand what you need. Can you share more code to clarify? The image shows your labels in that panel are already placed there and you've set the visible property to them. If the second row haven't listened to that event, can you share visibilitychanged code?

    Regards,


    Garros------


    Monday, July 01, 2013 7:56 AM
  • Hello,

    the problem is that the user control allways should look like this:

    But for some reasons, it does not. Visibilitychanged code does not alter visibility. So it doesn't really matters, but since you ask:

            void extendee_VisibleChanged(object sender, EventArgs e)
            {
                if (_extendees.ContainsKey(sender as Control))
                {
                    ProvideGuide(sender as Control);
                }
                else
                {
                    DebugLogger.Log("ImpressiveGuiGuideProvider", "extendee_VisibleChanged", "An unknown control triggered this event");
                }
            }
    
            private void ProvideGuide(Control control)
            {
                //Quit when control is null
                if (control == null)
                {
                    DebugLogger.Log("ImpressiveGuiGuideProvider", "ProvideGuide", "A null valued control requested a guiguide");
                    return;
                }
    
                //Get the first parent of the control that is either a form, tabpage or tabcontrol
                Control prnt = FindParent(control);
                //Get the location of the control on the form or tabpage
                Point p = FindLocation(control, prnt);
    
                //When parent is a tabcontrol and the item is a tabpage then some special things
                if (prnt is TabControl && control is TabPage && prnt.Parent != null)
                {
                    //Add the baloon to the form containing the tabcontrol
                    FindParent(prnt).Controls.Add(_extendees[control]);
                    //Visibility-level only depends on whether the showing is on or off
                    _extendees[control].Visible = GuiGuideManager.Visible;
    
                    //'Unbox' so we can easily handle the properties
                    TabControl tc = prnt as TabControl;
                    TabPage tp = control as TabPage;
    
                    //set location to top inside the button of the tabpage
                    _extendees[control].Location = new Point(p.X + (tc.TabPages.IndexOf(tp) * tc.ItemSize.Width) + (tc.ItemSize.Width / 2) - (_extendees[control].Width / 2), p.Y - tc.ItemSize.Height);
                }
                //When it's not a tabpage, everything gets easier
                else if (!(control is TabPage))
                {
                    //Add the balloon to the parent
                    prnt.Controls.Add(_extendees[control]);
                    //set visibility of control, depends on showing or not and visibility of linked control
                    _extendees[control].Visible = GuiGuideManager.Visible & control.Visible;
    
                    //Set location of balloon depending of alignment and if internal or external
                    SetGuideLocation(control, p);
                }
                //An unlinked tabpage...
                else if (prnt == control && control is TabPage)
                {
                    _extendees[control].Visible = GuiGuideManager.Visible & control.Visible;
                }
                _extendees[control].BringToFront();
            }
    
            private void SetGuideLocation(Control control, Point p)
            {
                //Define regular used items
                int height = _extendees[control].Height;
                int width = _extendees[control].Width;
                int halfHeight = height / 2;
                int halfWidth = width / 2;
                double overlayFactor = _extendees[control].OverlayFactor;
    
                //Calculate corrections dependant on overlay factor
                int bottomCorrection = (int)(-(height * overlayFactor));
                int upperCorrection = (int)(height * overlayFactor);
                int leftCorrection = (int)(width * overlayFactor);
                int rightCorrection = (int)(-(width * overlayFactor));
    
                switch (_extendees[control].Alignment)
                {
                    case ContentAlignment.BottomCenter:
                        _extendees[control].Location = new Point(p.X + (control.Width / 2) - halfWidth, p.Y + control.Height + bottomCorrection);
                        break;
                    case ContentAlignment.BottomLeft:
                        _extendees[control].Location = new Point(p.X - width + leftCorrection, p.Y + control.Height + bottomCorrection);
                        break;
                    case ContentAlignment.BottomRight:
                        _extendees[control].Location = new Point(p.X + control.Width + rightCorrection, p.Y + control.Height + bottomCorrection);
                        break;
                    case ContentAlignment.MiddleCenter:
                        _extendees[control].Location = new Point(p.X + (control.Width / 2) - halfWidth, p.Y + (control.Height / 2) - halfHeight);
                        break;
                    case ContentAlignment.MiddleLeft:
                        _extendees[control].Location = new Point(p.X - width + leftCorrection, p.Y + (control.Height / 2) - halfHeight);
                        break;
                    case ContentAlignment.MiddleRight:
                        _extendees[control].Location = new Point(p.X + control.Width + rightCorrection, p.Y + (control.Height / 2) - halfHeight);
                        break;
                    case ContentAlignment.TopCenter:
                        _extendees[control].Location = new Point(p.X + (control.Width / 2) - halfWidth, p.Y - height + upperCorrection);
                        break;
                    case ContentAlignment.TopLeft:
                        _extendees[control].Location = new Point(p.X - width + leftCorrection, p.Y - height + upperCorrection);
                        break;
                    case ContentAlignment.TopRight:
                        _extendees[control].Location = new Point(p.X + control.Width + rightCorrection, p.Y - height + upperCorrection);
                        break;
                }
            }
    
            private Point FindLocation(Control ctrl, Control prnt)
            {
                if (ctrl.Parent == prnt || ctrl.Parent == null)
                    return ctrl.Location;
                else
                {
                    Point p = FindLocation(ctrl.Parent, prnt);
                    p.X += ctrl.Location.X;
                    p.Y += ctrl.Location.Y;
                    return p;
                }
            }
    
            private Control FindParent(Control ctrl)
            {
                if (ctrl.Parent is Form || ctrl.Parent is TabPage || ctrl.Parent is TabControl || ctrl.Parent is UserControl)
                    return ctrl.Parent;
                else if (ctrl.Parent == null)
                {
                    return ctrl;
                }
                else if (ctrl.Parent is SplitContainer && ctrl.Parent.Parent == null)
                {
                    return ctrl;
                }
                else
                {
                    Control p = FindParent(ctrl.Parent);
                    return p;
                }
            }
    

    The above code is in a propertyprovider. It provides a control near the subscribers that acts like a static tooltip. But this has nothing to do with the visibility of the labels. Well, "nothing" isn't exactly true, because I need to set visibility in a specific order so that I can receive the visibilitychanged event.

    The problem is, My labels are not allways shown, and they should. I can't understand why not.

    Tuesday, July 02, 2013 8:17 AM
  • Sorry, to bump this! But the problem still exists! Maybe I should post a video to show you the current (undesired) behaviour?

    <embed height="420" src="http://v5.tinypic.com/player.swf?file=2zdq93s&s=5" type="application/x-shockwave-flash" width="440" />
    Original Video - More videos at TinyPic

    Because I'm such a n00b... click the 'Original Video' link please.

    Now, as you can see, on the left, I switch the tabpage, on the right you see 2 panels with content, they are shown dependent on the active tabpage! Now, you will see that the panel for tabpage etherCAT has strange visibility behaviour, the panel should allways be like the last visit.

    • Edited by Denny007 Monday, July 08, 2013 6:42 AM Add some explanation
    Monday, July 08, 2013 6:22 AM
  • Okay!

    So today I decided, to transform all my (Extra)Panels into UserControls, to have a smaller footprint on the form I was using them on (shrinked disgner code from 4 to 1k5 lines) and guess what?!

    No, it didn't got solved, if that was what you were thinking! It got worse, they all have those artifacts now! And they started to flicker real badly. I don't know about you, but this is getting to annoye me.

    Is it a bug or so? Every extra panel contains at maximum 60 controls (mostly labels).

    Tuesday, July 09, 2013 2:23 PM
  • I'm not sure I understand what you are doing.

    Are you hiding and showing every label?

    Is there a reason that you cannot simply hide the panel which contains them?

    For Each loops like this often result in undesired behaviour and you are better off using a For Next loop instead.

    Pseudo code:

    For int index = 0; index < myPanel.Controls.Count; index++
    {
        change visibility of myPanel.Controls[index]
    }



    Mick Doherty
    http://dotnetrix.co.uk
    http://glassui.codeplex.com

    • Marked as answer by Denny007 Wednesday, July 10, 2013 6:28 AM
    Tuesday, July 09, 2013 5:35 PM
  • I'm not sure I understand what you are doing.

    Are you hiding and showing every label?

    Is there a reason that you cannot simply hide the panel which contains them?

    For Each loops like this often result in undesired behaviour and you are better off using a For Next loop instead.

    Pseudo code:

    For int index = 0; index < myPanel.Controls.Count; index++
    {
        change visibility of myPanel.Controls[index]
    }



    Mick Doherty
    http://dotnetrix.co.uk
    http://glassui.codeplex.com

    Yes! That is exactly what I am doing, I do this because the 'Visibilitychanged' event, of every control must get fired. When I would hide the panel only, the controls inside would not fire their 'visibilitychanged' event. I have tested this, yes this is sadly true.

    I'll try and test the for next loop instead, but can you explain to me why a foreach loop doesn't work?

    Thanks!

    Tuesday, July 09, 2013 6:09 PM
  • I'll try and test the for next loop instead, but can you explain to me why a foreach loop doesn't work?


    I'm not sure why it doesn't work, but this is a know issue (at least, that is, I know about it and have seen it discussed many times in these forums).

    Mick Doherty
    http://dotnetrix.co.uk
    http://glassui.codeplex.com

    Tuesday, July 09, 2013 6:46 PM
  • I'm not sure I understand what you are doing.

    Are you hiding and showing every label?

    Is there a reason that you cannot simply hide the panel which contains them?

    For Each loops like this often result in undesired behaviour and you are better off using a For Next loop instead.

    Pseudo code:

    For int index = 0; index < myPanel.Controls.Count; index++
    {
        change visibility of myPanel.Controls[index]
    }



    Mick Doherty
    http://dotnetrix.co.uk
    http://glassui.codeplex.com

    You sir! Are my HERO!

    Changing my foreaches to for next loops solved the problem, I'm very gratefull! Thanks a lot!

    Wednesday, July 10, 2013 6:27 AM