有没有一种简单的方法来动画ScrollableControl.ScrollControlIntoView方法?

时间:2008-10-06 19:08:48

标签: c# .net vb.net winforms

我有一个表单,其中控件动态添加到Panel。但是,当它们这样做时,它们会多次添加到折叠下方(容器的底部)。 .NET Framework提供这种ScrollControlIntoView方法很不错,但是为了增加可用性,如果有一种简单的动画方法也很好,这样用户就可以很容易地理解Panel是自动滚动的。

有没有人遇到过这个问题或有任何关于如何处理它的想法?

2 个答案:

答案 0 :(得分:1)

您可以继承Panel,添加Timer并覆盖ScrollIntoView(),以便在新AnimatedScrollPanel内完成所有操作。我非常确定您必须这样做才能使用某些protected方法,例如ScrollToControl()返回Point(由ScrollIntoView使用)

答案 1 :(得分:1)

@Joel

谢谢!我已经知道了,在反射器的帮助下做起来并不困难。可能有方法来优化它,但这是我必须开始的。碰巧我在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 });
    }
}