【发布时间】:2008-10-06 19:08:47
【问题描述】:
我有一个表单,其中控件被动态添加到面板中。但是,当它们这样做时,它们会多次添加到折叠下方(容器底部)。很高兴 .NET Framework 提供了这个 ScrollControlIntoView 方法,但是,为了增加可用性,如果有一种简单的动画方法让用户很容易理解 Panel 是自动滚动的,那就太好了。
有没有人遇到过这种情况或对如何解决有任何想法?
【问题讨论】:
我有一个表单,其中控件被动态添加到面板中。但是,当它们这样做时,它们会多次添加到折叠下方(容器底部)。很高兴 .NET Framework 提供了这个 ScrollControlIntoView 方法,但是,为了增加可用性,如果有一种简单的动画方法让用户很容易理解 Panel 是自动滚动的,那就太好了。
有没有人遇到过这种情况或对如何解决有任何想法?
【问题讨论】:
您可以继承Panel,添加Timer,并覆盖ScrollIntoView(),以便在您的新AnimatedScrollPanel 中完成这一切。我很确定您必须这样做才能使用某些protected 方法,例如返回Point 的ScrollToControl()(由ScrollIntoView 使用)。
【讨论】:
@乔尔
谢谢!我明白了,在反射器的帮助下,这并不难。可能有优化它的方法,但这是我必须开始的。碰巧我需要在 FlowLayoutPanel 中使用此功能,但它适用于从 ScrollableControl 继承的任何内容。
编辑:由于@Joel B Fant 指出我没有删除委托,我更改了一些内容,而是无限期地保留计时器对象。我相信我已经通过将委托分配给一个 EventHandler 对象来减轻这种担忧,这样它就可以在自身内部被删除。
using System;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
public class AnimatedScrollFlowLayoutPanel : FlowLayoutPanel
{
public new void ScrollControlIntoView(Control activeControl)
{
if (((this.IsDescendant(activeControl) && this.AutoScroll) &&
(this.HScroll || this.VScroll)) && (((activeControl != null) &&
(ClientRectangle.Width > 0)) && (ClientRectangle.Height > 0)))
{
Point point = this.ScrollToControl(activeControl);
int x = DisplayRectangle.X, y = DisplayRectangle.Y;
bool scrollUp = x < point.Y;
bool scrollLeft = y < point.X;
Timer timer = new Timer();
EventHandler tickHandler = null;
tickHandler = delegate {
int jumpInterval = ClientRectangle.Height / 10;
if (x != point.X || y != point.Y)
{
y = scrollUp ?
Math.Min(point.Y, y + jumpInterval) :
Math.Max(point.Y, y - jumpInterval);
x = scrollLeft ?
Math.Min(point.X, x + jumpInterval) :
Math.Max(point.X, x - jumpInterval);
this.SetScrollState(8, false);
this.SetDisplayRectLocation(x, y);
this.SyncScrollbars(true);
}
else
{
timer.Stop();
timer.Tick -= tickHandler;
}
};
timer.Tick += tickHandler;
timer.Interval = 5;
timer.Start();
}
}
internal bool IsDescendant(Control descendant)
{
MethodInfo isDescendantMethod = typeof(Control).GetMethod(
"IsDescendant", BindingFlags.NonPublic | BindingFlags.Instance);
return (bool)isDescendantMethod.Invoke(this, new object[] { descendant });
}
private void SyncScrollbars(bool autoScroll)
{
MethodInfo syncScrollbarsMethod = typeof(ScrollableControl).GetMethod(
"SyncScrollbars", BindingFlags.NonPublic | BindingFlags.Instance);
syncScrollbarsMethod.Invoke(this, new object[] { autoScroll });
}
}
【讨论】: