Question

J'écris une application .NET qui utilise le défilement automatique pour un panneau de mise en page dans une boîte de dialogue. Il semble que chaque fois que je redimensionnez la fenêtre pour que les barres de défilement verticales doivent apparaître, la barre de défilement horizontale apparaît automatiquement aussi. En regardant de près à elle, la deuxième barre de défilement me permet maintenant de faire défiler la fenêtre en 16 pixels (la largeur de l'autre) scrollbar. Alors fenêtres semble penser que je besoin d'un espace client qui est au moins aussi large qu'il était avant la barre de défilement verticale est apparu.

Si je redimensionne maintenant la fenêtre à 16 pixels plus large (de sorte que ma zone de fenêtre est aussi large que ce qu'elle était avant la barre de défilement est apparu), la barre de défilement disparaît. Maintenant, si je remets à la côte en arrière jusqu'à ce qu'il était, il reste à l'écart.

Il me semble qu'il ya un bogue dans le système où la largeur minimale est en quelque sorte collante, mais upsizing et downsizging la fenêtre (avec la souris, et sans tuching les scrollbars API liées) efface la condition

Quelqu'un sait-il d'une solution de contournement, ou que je fais quelque chose pour déclencher Windows?

Pas de solution correcte

Autres conseils

Oui, je pense que vous avez déjà diagnostiqué correctement le problème. Il est un effet secondaire méchant, disons, la barre de défilement vertical apparaissant et ayant besoin d'espace, ce qui rend l'espace client disponible plus petit. Trop petit pour tenir les commandes, maintenant faire apparaître la barre de défilement horizontale. Il est en fait bistables, la barre horizontale peut vaciller sur et en dehors, dans certains cas.

Pour éviter cet effet, le moteur de mise en page devrait faire des passes multiples par la mise en page, traitant de l'espace client changeant. Elle a toutefois fait une seule passe. Ce qui semble sage, cela pourrait être une boucle sans fin potentiellement jamais. Je ne sais pas d'une solution décente pour cela. Votre nom d'utilisateur sera probablement redimensionner la fenêtre assez grand pour se débarrasser d'au moins l'une des barres de défilement.

Ceci est un bug connu dans Windows - ici

La meilleure façon de résoudre ce problème est de mettre le panneau de configuration de table autosized dans un autre panneau qui est amarrée à la forme principale et définie avec autoscroll = true

Alors, vous n'êtes plus en utilisant la TableLayoutPanel pour faire défiler qui est bogué, vous utilisez le panneau pour faire défiler et le TableLayoutPanel est à l'intérieur du panneau

Je ne l'ai pas remarqué exactement le comportement que vous décrivez, mais se sont heurtées à des situations où l'apparition de la barre de défilement verticale fait une barre de défilement horizontale nécessaire.

Vous pouvez définir le contenu du panneau pour permettre la largeur de la barre de défilement, par exemple si j'ai un ListBox dans un Panel:

listBox1.Width = panel2.Width - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth;

HTH

Je viens rencontré ce problème. Le correctif j'était de mettre Scrollable à false puis à true. Voici un exemple avec un événement ListView de Resize:

private void myListView_Resize(object sender, EventArgs e)
{
 this.SuspendLayout();

 //Code to do various resizing stuff

 //Force Scrollbar Recalculation
 myListView.Scrollable = false;
 myListView.Scrollable = true;
 this.ResumeLayout(false);
 this.PerformLayout();
}

Si Scrollable est pas toujours vrai, vous pouvez faire le recalcul conditionnel.

Bien que ce soit une vieille question, il est encore un problème dans .NET 4. Après avoir lu autant que je pouvais trouver sur la question, j'ai roulé une combinaison de solutions dans une classe d'aide.

Tout d'abord, voici le résultat que je visais ... J'ai un panneau qui contient une variété de contrôles. Le contrôle enfant, et leur taille, peuvent changer en fonction de l'activité des utilisateurs. Je veux que le panneau à redimensionner horizontalement afin qu'il n'y ait jamais une barre de défilement horizontale, mais s'il n'y a pas assez de place à la verticale, je veux la barre de défilement verticale apparaisse. De plus, la barre de défilement vertical ne peut couvrir aucun de mes contrôles enfants quand il apparaît, et je ne veux pas laisser un espace pour lui quand il est pas nécessaire.

Les deux « bugs » que ma classe d'aide tente de fixer sont tout d'abord, ne jamais afficher la barre de défilement horizontale, et la seconde, lorsque la barre de défilement verticale apparaît, ont automatiquement augmenter la largeur du panneau pour l'accueillir.

Mes hypothèses sont que le panneau est réglé sur AutoSize et AutoScroll, et les contrôles enfants sont mis à autoSize ainsi.

La solution

La classe d'aide se fixe au panneau (en manipulant la peinture et les événements SizeChanged) et fait deux choses. Tout d'abord, il désactive la barre de défilement horizontale. Ce n'est pas aussi facile que cela puisse paraître, et je l'ai trouvé la solution à ce problème ici barre de défilement horizontale réponse par KBV Subrahmanyam . En second lieu, en réponse à la peinture et les événements SizeChanged, ainsi qu'une minuterie de fond, il vérifie si la propriété Visible de la barre de défilement verticale a changé. Dans ce cas, la classe aide modifie le droit de propriété Rembourrage du panneau pour ajouter ou supprimer l'espace supplémentaire de la barre de défilement nécessite. L'utilisation des différents événements du panneau et la minuterie sont nécessaires parce que .NET pas les événements du tout pour la barre de défilement (une grande à mon humble avis de défaut de conception).

Une fois que le point final est que vous ne pouvez rien faire qui modifie la taille du panneau lors de la manipulation de l'événement SizeChanged. Bad Stuff (tm) se produit si vous le faites. Donc, si je dois changer le rembourrage en raison d'un événement SizeChanged, je planifie que le changement pour plus tard.

Quoi qu'il en soit, voici le code pour la classe d'aide. Il suppose que vous avez toutes les déclarations appropriées « à l'aide », dont une pour System.Threading ...

/// <summary>
/// This class is intended to beat the AutoSize and AutoScroll features into submission!
/// 
/// Or, at least getting them to work the way I want them to (which may not be the way 
/// others think they should work).
/// 
/// This class will force a panel that has AutoSize enabled to actually increase its
/// width as appropriate when the AutoScroll Vertical scroll bar becomes visible.
/// I like this better than attempting to 'reserve' space for the Vertical scroll bar,
/// which wastes space when the scroll bar is not needed, and leaves ugly gaps in
/// your user interface.
/// </summary>
public class AutoScrollFixer
{
    /// <summary>
    /// This is the panel we are 'fixing'
    /// </summary>
    private Panel _panel;

    /// <summary>
    /// This field keeps track of the original value for
    /// the right padding property of the panel.
    /// </summary>
    private int _originalRightPadding = 0;

    /// <summary>
    /// We use this flag to prevent recursion problems.
    /// </summary>
    private bool _adjusting = false;

    /// <summary>
    /// This flag keeps track of the last known state of the scroll bar.
    /// </summary>
    private bool _lastScrollBarVisible = false;

    /// <summary>
    /// We use a timer to check the scroll bar state every so often.
    /// This is necessary since .NET (in another stunning piece of
    /// architecture from Microsoft) provides absolutely no events
    /// attached to the scroll bars of a panel.
    /// </summary>
    private System.Windows.Forms.Timer _timer = new System.Windows.Forms.Timer();

    /// <summary>
    /// Construct an AutoScrollFixer and attach it to the provided panel.
    /// Once created, there is no particular reason to keep a reference 
    /// to the AutoScrollFixer in your code.  It will silently do its thing
    /// in the background.
    /// </summary>
    /// <param name="panel"></param>
    public AutoScrollFixer(Panel panel)
    {
        _panel = panel;
        _originalRightPadding = panel.Padding.Right;

        EnableVerticalAutoscroll(_panel);
        _lastScrollBarVisible = _panel.VerticalScroll.Visible;

        _panel.Paint += (s, a) =>
        {
            AdjustForVerticalScrollbar();
        };

        _panel.SizeChanged += (s, a) =>
        {
            //
            //  We can't do something that changes the size while handling
            //  a size change.  So, if an adjustment is needed, we will
            //  schedule it for later.
            //
            if (_lastScrollBarVisible != _panel.VerticalScroll.Visible)
            {
                AdjustLater();
            }
        };

        _timer.Tick += (s, a) =>
        {
            //
            //  Sadly, the combination of the Paint event and the SizeChanged event
            //  is NOT enough to guarantee that we will catch a change in the
            //  scroll bar status.  So, as a last ditch effort, we will check
            //  for a status change every 500 mSecs.  Yup, this is a hack!
            //
            AdjustForVerticalScrollbar();
        };

        _timer.Interval = 500;
        _timer.Start();
    }


    /// <summary>
    /// Enables AutoScroll, but without the Horizontal Scroll bar.
    /// Only the Vertical Scroll bar will become visible when necessary
    /// 
    /// This method is based on this StackOverflow answer ...
    /// https://stackoverflow.com/a/28583501/2175233
    /// </summary>
    /// <param name="panel"></param>
    public static void EnableVerticalAutoscroll( Panel panel )
    {
        panel.AutoScroll = false;
        panel.HorizontalScroll.Enabled = false;
        panel.HorizontalScroll.Visible = false;
        panel.HorizontalScroll.Maximum = 0;
        panel.AutoScroll = true;
    }


    /// <summary>
    /// Queue AdjustForVerticalScrollbar to run on the GUI thread after the current
    /// event has been handled.
    /// </summary>
    private void AdjustLater()
    {
        ThreadPool.QueueUserWorkItem((t) => 
        {
            Thread.Sleep(200);
            _panel.BeginInvoke((Action)(() =>
            {
                AdjustForVerticalScrollbar();
            }));
        });
    }


    /// <summary>
    /// This is where the real work gets done.  When this method is called, we will
    /// simply set the right side padding on the panel to make room for the
    /// scroll bar if it is being displayed, or reset the padding value to 
    /// its original value if not.
    /// </summary>
    private void AdjustForVerticalScrollbar()
    {
        if (!_adjusting)
        {
            try
            {
                _adjusting = true;

                if (_lastScrollBarVisible != _panel.VerticalScroll.Visible)
                {
                    _lastScrollBarVisible = _panel.VerticalScroll.Visible;

                    Padding p = _panel.Padding;
                    p.Right = _lastScrollBarVisible ? _originalRightPadding + System.Windows.Forms.SystemInformation.VerticalScrollBarWidth + 2 : _originalRightPadding;
                    _panel.Padding = p;
                    _panel.PerformLayout();
                }
            }

            finally
            {
                _adjusting = false;
            }
        }
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top