我正在.net中编写一个应用程序,它在对话框中使用autoscroll作为布局面板。 似乎每当我调整窗口大小以便显示垂直滚动条时,水平滚动条也会自动出现。仔细观察它,第二个滚动条现在允许我将窗口滚动16个像素(另一个滚动条的宽度)。所以Windows似乎认为我需要一个至少与垂直滚动条出现之前一样宽的客户区。
如果我现在将窗口调整为宽16像素(使我的窗口区域与滚动条出现之前一样宽),滚动条就会消失。现在,如果我将其重新调整为原来的状态,它就会消失。
所以在我看来,系统中存在一个错误,其中最小宽度有点粘,但是放大和缩小窗口(使用鼠标,而不调整滚动条相关的API)会清除条件
有人知道某种解决方法,或者我是否正在做一些绊倒Windows的事情?
答案 0 :(得分:5)
是的,我认为你已经正确诊断出了这个问题。这是一个令人讨厌的副作用,例如,垂直滚动条出现并需要空间,使可用的客户区域更小。太小而不适合控件,现在也会出现水平滚动条。它实际上是双稳态的,在某些情况下水平条可以闪烁。
为了避免这种影响,布局引擎必须在布局中进行多次传递,处理不断变化的客户区域。然而它只通过一次。这听起来很明智,这可能是一个永无止境的循环。我不知道对此有什么好处。您的用户可能只需调整窗口大小,以便至少删除其中一个滚动条。
答案 1 :(得分:5)
这是Windows中的已知错误 - here
解决此问题的最佳方法是将表格布局面板自动调整到另一个面板中,该面板停靠在主窗体上并使用autoscroll = true进行设置
因此,您不再使用tablelayoutpanel滚动哪个有问题,您可以使用面板滚动并且tablelayoutpanel位于面板内
答案 2 :(得分:2)
我没有完全注意到您描述的行为,但遇到了垂直滚动条的外观需要水平滚动条的情况。
您可以设置面板的内容以允许滚动条的宽度,例如,如果ListBox
中有Panel
:
listBox1.Width = panel2.Width - System.Windows.Forms.SystemInformation.VerticalScrollBarWidth;
HTH
答案 3 :(得分:0)
我刚遇到这个问题。我使用的修复方法是将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
并非总是如此,则可以重新计算条件。
答案 4 :(得分:0)
尽管这是一个老问题,但它仍然是.NET 4中的一个问题。尽管我已经在这个问题上找到了尽可能多的内容,但我已经将一组解决方案组合成了一个帮助类。
首先,这是我拍摄的结果......我有一个包含各种控件的面板。子控件及其大小可以根据用户活动进行更改。我希望面板水平调整大小,以便永远不会有水平滚动条,但如果没有足够的垂直空间,我希望显示垂直滚动条。此外,垂直滚动条在出现时无法覆盖我的任何儿童控件,并且在不需要时我不想为它留下空隙。
这两个错误'我的助手类试图修复的是第一个,从不显示水平滚动条,其次,当出现垂直滚动条时,面板的宽度会自动增加以适应它。
我的假设是面板设置为AutoSize和AutoScroll,子控件也设置为AutoSize。
辅助类将自身附加到面板(通过处理Paint和SizeChanged事件)并执行两项操作。首先,它禁用水平滚动条。这并不像听起来那么容易,我在这里找到了解决这个问题的方法Horizontal scroll bar answer by Kbv Subrahmanyam。其次,为了响应Paint和SizeChanged事件以及后台计时器,它会检查垂直滚动条的Visible属性是否已更改。如果是这样,辅助类会改变面板的右边距属性,以添加或删除滚动条所需的额外空间。需要使用各种面板事件和计时器,因为.NET为滚动条公开了 no 事件(一个很大的设计缺陷恕我直言)。
最后一点是,在处理SizeChanged事件时,您无法执行任何更改面板大小的操作。如果你这样做,就会发生Bad Stuff(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;
}
}
}
}