【问题标题】:.net scrollbar autoscroll problem.net 滚动条自动滚动问题
【发布时间】:2011-04-17 20:21:38
【问题描述】:

我正在.net 中编写一个应用程序,该应用程序使用自动滚动作为对话框中的布局面板。 似乎每当我调整窗口大小以使垂直滚动条出现时,水平滚动条也会自动出现。仔细观察,第二个滚动条现在允许我将窗口滚动 16 个像素(另一个滚动条的宽度)。所以 windows 似乎认为我需要一个至少与垂直滚动条出现之前一样宽的客户区。

如果我现在将窗口的大小调整为宽 16 像素(这样我的窗口区域就与滚动条出现之前一样宽),滚动条就会消失。现在,如果我将其调整回原来的大小,它就会消失。

所以在我看来,系统中存在一个错误,即最小宽度在某种程度上是粘滞的,但是放大和缩小窗口(使用鼠标,并且不调整与滚动条相关的 API)会清除这种情况

是否有人知道解决方法,或者我是否正在做一些事情来绊倒 Windows?

【问题讨论】:

  • 我以前也遇到过这种情况;通过谷歌偶然发现了你的问题。我通常的解决方法是用垂直滚动条的宽度填充我的布局(下面有人已经回答了)。

标签: c# .net resize autoscroll


【解决方案1】:

是的,我认为您已经正确诊断出问题。这是一个令人讨厌的副作用,例如,垂直滚动条出现并需要空间,从而使可用的客户区更小。太小而无法容纳控件,现在还会显示水平滚动条。它实际上是双稳态的,水平条在某些情况下会闪烁。

为避免这种影响,布局引擎必须多次通过布局,以处理不断变化的客户区。然而,它只通过一次。这听起来很明智,这可能是一个潜在的永无止境的循环。我不知道有什么合适的解决方法。您的用户可能只需将窗口大小调整到足够大,以消除至少一个滚动条。

【讨论】:

  • 嗯,我正在查看 xnview 以了解我想做的事情,而 xnview 的行为做得很好。但我怀疑他们没有使用自动滚动功能。但是自动滚动非常方便,太糟糕了,它不能正常工作。太糟糕了,微软无法做到这一点。令人失望的是微软没有。
  • 不确定这意味着什么。但是,是的,当库不支持自动滚动时,这不会出错。如果只有窗口的滚动条在窗口之外,那将永远不会成为问题。不过,我真的很喜欢他们试图让它发挥作用。
【解决方案2】:

这是 Windows 中的一个已知错误 - here

解决此问题的最佳方法是将自动调整大小的表格布局面板放在另一个面板中,该面板停靠在主窗体并设置为 autoscroll = true

所以您不再使用有问题的 tablelayoutpanel 滚动,您使用面板滚动并且 tablelayoutpanel 在面板内

【讨论】:

    【解决方案3】:

    我没有注意到您描述的确切行为,但遇到了垂直滚动条的出现需要水平滚动条的情况。

    您可以设置面板的内容以允许滚动条的宽度,例如,如果我在 Panel 中有一个 ListBox

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

    HTH

    【讨论】:

      【解决方案4】:

      我刚遇到这个问题。我使用的修复方法是将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 不总是正确的,您可以使重新计算有条件。

      【讨论】:

      • 这也是我最终所做的,但我遇到了一个滚动条一直停留直到两个滚动条都消失的问题。这是我的问题的性质。我最终放弃了尝试让 Windows 做正确的事情,并停止使用自动滚动功能。
      【解决方案5】:

      尽管这是一个老问题,但它在 .NET 4 中仍然是一个问题。在阅读了尽可能多的关于该问题的内容后,我将解决方案的组合整合到一个帮助程序类中。

      首先,这是我要拍摄的结果……我有一个包含各种控件的面板。子控件及其大小可以根据用户活动而改变。我希望面板水平调整大小,以便永远不会有水平滚动条,但如果垂直空间不足,我希望出现垂直滚动条。此外,垂直滚动条出现时无法覆盖我的任何子控件,并且我不想在不需要时为它留下空隙。

      我的助手类试图修复的两个“错误”是第一个,从不显示水平滚动条,其次,当垂直滚动条出现时,面板的宽度会自动增加以适应它。

      我的假设是面板设置为 AutoSize 和 AutoScroll,子控件也设置为 AutoSize。

      解决方案

      帮助类将自己附加到面板(通过处理 Paint 和 SizeChanged 事件)并做两件事。首先,它禁用水平滚动条。这并不像听起来那么容易,我在这里找到了解决这个问题的方法Horizontal scroll bar answer by Kbv Subrahmanyam。其次,响应 Paint 和 SizeChanged 事件以及后台计时器,它检查垂直滚动条的 Visible 属性是否已更改。如果是这样,帮助程序类会更改面板的 Right Padding 属性以添加或删除滚动条所需的额外空间。需要使用各种面板事件和计时器,因为 .NET 完全为滚动条公开 no 事件(恕我直言,这是一个很大的设计缺陷)。

      最后一点是,在处理 SizeChanged 事件时,您不能做任何改变面板大小的事情。如果您这样做,就会发生坏事(tm)。因此,如果由于 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;
                  }
              }
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-02
        相关资源
        最近更新 更多