.net滚动条自动滚动问题

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

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

所以在我看来,系统中存在一个错误,其中最小宽度有点粘,但是升级和缩小窗口(使用鼠标,而不调整滚动条相关的API)可以清除条件

有人知道一个解决方法,或者我正在做什么来绊倒Windows?

是的,我认为你已经正确诊断出了这个问题。 这是一个令人讨厌的副作用,例如,垂直滚动条出现并需要空间,使可用的客户区域更小。 太小以适应控件,现在也使水平滚动条出现。 它实际上是双稳态的,在某些情况下,水平条可以闪烁。

为了避免这种影响,布局引擎必须在布局中进行多次传递,处理不断变化的客户区域。 然而它只通过一次。 这听起来很明智,这可能是一个永无止境的循环。 我不知道对此有什么好处。 您的用户可能只是将窗口大小调整到足以摆脱至少一个滚动条。

这是Windows中的已知错误 – 这里

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

因此,您不再使用tablelayoutpanel来滚动哪个有错误,您可以使用面板滚动并且tablelayoutpanel位于面板内

我没有完全注意到您描述的行为,但遇到了垂直滚动条的外观需要水平滚动条的情况。

您可以设置面板的内容以允许滚动条的宽度,例如,如果我在PanelListBox

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

HTH

我刚遇到这个问题。 我使用的修复是将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不总是true,则可以使重新计算成为条件。

尽管这是一个老问题,但它仍然是.NET 4中的一个问题。尽管我已经在这个问题上找到了尽可能多的内容,但我已经将一组解决方案集成到了一个帮助类中。

首先,这是我拍摄的结果……我有一个包含各种控件的面板。 子控件及其大小可以根据用户活动进行更改。 我希望面板水平resize,以便永远不会有水平滚动条,但如果没有足够的垂直空间,我希望显示垂直滚动条。 此外,垂直滚动条在出现时不能覆盖我的任何儿童控件,我不想在不需要时给它留一个空隙。

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

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

解决方案

辅助类将自身附加到面板(通过处理Paint和SizeChanged事件)并执行两项操作。 首先,它禁用水平滚动条。 这并不像听起来那么容易,我在这里找到了这个问题的解决方案。 水平滚动条由Kbv Subrahmanyam回答 。 其次,为了响应Paint和SizeChanged事件以及后台计时器,它会检查垂直滚动条的Visible属性是否已更改。 如果是这样,辅助类会改变面板的右边距属性,以添加或删除滚动条所需的额外空间。 需要使用各种面板事件和计时器,因为.NET 根本没有为滚动条公开任何事件(一个大的设计缺陷恕我直言)。

最后一点是,在处理SizeChanged事件时,您无法执行任何更改面板大小的操作。 如果你这样做,就会发生Bad Stuff(tm)。 因此,如果我需要更改由于SizeChanged事件导致的填充,我会安排稍后更改。

无论如何,这是帮助类的代码。 它假设您拥有所有相应的“使用”语句,包括一个用于System.Threading …

 ///  /// 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. ///  public class AutoScrollFixer { ///  /// This is the panel we are 'fixing' ///  private Panel _panel; ///  /// This field keeps track of the original value for /// the right padding property of the panel. ///  private int _originalRightPadding = 0; ///  /// We use this flag to prevent recursion problems. ///  private bool _adjusting = false; ///  /// This flag keeps track of the last known state of the scroll bar. ///  private bool _lastScrollBarVisible = false; ///  /// 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. ///  private System.Windows.Forms.Timer _timer = new System.Windows.Forms.Timer(); ///  /// 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. ///  ///  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(); } ///  /// 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 ///  ///  public static void EnableVerticalAutoscroll( Panel panel ) { panel.AutoScroll = false; panel.HorizontalScroll.Enabled = false; panel.HorizontalScroll.Visible = false; panel.HorizontalScroll.Maximum = 0; panel.AutoScroll = true; } ///  /// Queue AdjustForVerticalScrollbar to run on the GUI thread after the current /// event has been handled. ///  private void AdjustLater() { ThreadPool.QueueUserWorkItem((t) => { Thread.Sleep(200); _panel.BeginInvoke((Action)(() => { AdjustForVerticalScrollbar(); })); }); } ///  /// 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. ///  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; } } } }