проблема с автоматической прокруткой полосы прокрутки .net

StackOverflow https://stackoverflow.com/questions/3805351

  •  25-09-2019
  •  | 
  •  

Вопрос

Я пишу приложение на .net, которое использует автоматическую прокрутку для панели макета в диалоговом окне.Кажется, что всякий раз, когда я изменяю размер окна так, чтобы появлялись вертикальные полосы прокрутки, автоматически появляется и горизонтальная полоса прокрутки.Присмотревшись повнимательнее, я вижу, что вторая полоса прокрутки теперь позволяет мне прокручивать окно на 16 пикселей (ширина другой полосы прокрутки).Итак, Windows, похоже, думает, что мне нужна клиентская область, которая была бы по крайней мере такой же широкой, как до появления вертикальной полосы прокрутки.

Если я теперь изменю размер окна на 16 пикселей шире (чтобы область моего окна была такой же широкой, какой она была до появления полосы прокрутки), полоса прокрутки исчезнет.Теперь, если я изменю его размер обратно до того, каким он был, он останется в стороне.

Таким образом, мне кажется, что в системе есть ошибка, из-за которой минимальная ширина является какой-то липкой, но увеличение и уменьшение размера окна (с помощью мыши и без использования API, связанных с полосами прокрутки) устраняет условие

Кто-нибудь знает об обходном пути, или я делаю что-то, чтобы отключить Windows?

Нет правильного решения

Другие советы

Да, я думаю, вы уже правильно диагностировали проблему. Это неприятный побочный эффект, скажем, вертикальная прокрутка, появляющаяся и нуждающееся в пространстве, что делает доступную область клиента меньше. Слишком маленький, чтобы соответствовать элементам управления, теперь появляются также горизонтальная прокрутка. На самом деле это Bi-State, горизонтальный бар может мерцать и выключить в определенных случаях.

Чтобы избежать этого эффекта, механизм макета должен будет делать несколько проходов через макет, имея дело с изменяющейся областью клиента. Это, однако, только делает один проход. Что звучит мудро, это может быть потенциально никогда не заканчивать цикл. Я не знаю о приличном исправлении для этого. Ваш пользователь, вероятно, просто изменит размер окна, достаточно большой, чтобы избавиться от хотя бы одного из прокрутков.

Это известная ошибка в Windows - здесь

Лучший способ исправить это - поместить панель компоновки таблицы с автоматическим изменением размера внутри другой панели, которая прикреплена к основной форме и установлена с помощью autoscroll = true

Таким образом, вы больше не используете tablelayoutpanel для прокрутки, которая глючит, вы используете панель для прокрутки, а tablelayoutpanel находится внутри панели

Я не заметил именно то поведение, которое вы описываете, но столкнулись с ситуациями, когда появление вертикальной полосы Scrollbar обеспечивает горизонтальную прокрутку.

Вы можете установить содержимое панели, чтобы позволить ширину прокрутки, например, если у меня есть ListBox в Panel:

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

Емкость

Я только что столкнулся с этой проблемой. Исправление, которое я использовал, должен был установить Scrollable к false а потом к true. Отказ Вот пример с ListView 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();
}

Если Scrollable Не всегда правда, вы можете сделать условный пересчет.

Несмотря на это старый вопрос, это все еще проблема в .NET 4. Читать столько, сколько я мог найти по этому вопросу, я прокатил комбинацию решений в класс помощника.

Во-первых, вот результат, к которому я стреляю ... У меня есть панель, которая содержит различные элементы управления. Детские элементы управления, а их размеры могут измениться на основе пользовательской активности. Я хочу, чтобы панель было разместить по горизонтали, чтобы не было горизонтальной полосы прокрутки, но если не хватает места вертикально, я хочу появиться вертикальная полоса прокрутки. Кроме того, вертикальная полоса прокрутки не может охватывать любой элемент управления моего ребенка, когда оно появляется, и я не хочу оставлять пробел для него, когда он не нужен.

Две «ошибки», которые пытаются исправить мой класс помощника, сначала не показывают горизонтальную полосу прокрутки, а во-вторых, когда появляется вертикальная полоса прокрутки, у вас появляется ширина панели автоматически, чтобы вместить ее.

Мои предположения заключаются в том, что панель устанавливается на AutoSize и AutoScroll, а дочерние элементы управления установлены для автосазования.

Решение

Класс в хелпера прикрепляется к панели (путем обработки краской и сизехованных событий) и делает две вещи. Во-первых, он отключает горизонтальную полосу прокрутки. Это не так просто, как это звучит, и я нашел решение этой проблемы здесь Горизонтальный батончик прокрутки ответа от KBV Subrahmanyam. Отказ Во-вторых, в ответ на мероприятия по краскам и сизечана, а также на фоне таймера, он проверяет, изменено ли видимое свойство вертикальной полосы прокрутки. Если это так, класс помощника изменяет свойство правой накладки панели, чтобы добавить или удалить дополнительное пространство, требуется полоса прокрутки. Использование различных панельных событий и таймера требуется, потому что .NET подвергает нет События вообще для прокрутки стержня (большой дизайн Defaw IMHO).

После окончательного момента то, что вы не можете сделать все, что изменяет размер панели при обращении со событием SizeChanged. Плохие вещи (тм) происходят, если вы сделаете. Итак, если мне нужно изменить прокладку из-за мероприятия SizeChangEned, я запланирую это изменение на потом.

Во всяком случае, вот код для класса помощника. Предполагается, что у вас есть все подходящие «Использование» отчетов, включая одну для 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;
            }
        }
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top