Проблема автопрокрутки полосы прокрутки .net - PullRequest
6 голосов
/ 27 сентября 2010

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

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

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

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

Ответы [ 5 ]

5 голосов
/ 11 февраля 2011

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

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

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

5 голосов
/ 27 сентября 2010

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

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

2 голосов
/ 27 сентября 2010

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

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

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

HTH

0 голосов
/ 28 января 2016

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

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

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

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

Решение

Вспомогательный класс присоединяется к панели (путем обработки событий Paint и SizeChanged) и выполняет две функции.Во-первых, он отключает горизонтальную полосу прокрутки.Это не так просто, как кажется, и я нашел решение этой проблемы здесь Горизонтальная полоса прокрутки в ответе Kbv Subrahmanyam .Во-вторых, в ответ на события Paint и SizeChanged, а также таймер фона он проверяет, изменилось ли свойство Visible вертикальной полосы прокрутки.Если это так, вспомогательный класс изменяет свойство Right Padding панели, чтобы добавить или удалить дополнительное пространство, необходимое для полосы прокрутки.Требуется использование различных событий панели и таймера, потому что .NET вообще не выставляет никаких событий для полосы прокрутки (большой недостаток дизайна ИМХО).

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

В любом случае, вот код для вспомогательного класса.Предполагается, что у вас есть все соответствующие операторы использования, в том числе для 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;
            }
        }
    }
}
0 голосов
/ 01 октября 2010

Я только что столкнулся с этой проблемой.Исправление, которое я использовал, состояло в том, чтобы установить 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 не всегда верно, вы можете сделать пересчет условным.

...