Есть ли простой способ анимировать метод ScrollableControl.ScrollControlIntoView? - PullRequest
2 голосов
/ 06 октября 2008

У меня есть форма, в которой элементы управления динамически добавляются в Panel. Однако, когда они это делают, они много раз добавляются ниже сгиба (дно контейнера). Приятно, что .NET Framework предоставляет этот метод ScrollControlIntoView, однако для удобства использования было бы также неплохо, если бы существовал простой способ анимации, чтобы пользователю было легко понять, что Panel автоматически прокручивается.

Кто-нибудь когда-либо сталкивался с этим или есть какие-либо идеи относительно того, как справиться с этим?

Ответы [ 2 ]

1 голос
/ 07 октября 2008

@ 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 });
    }
}
1 голос
/ 06 октября 2008

Вы можете создать подкласс Panel, добавить Timer и переопределить ScrollIntoView(), чтобы сделать все это в пределах вашего нового AnimatedScrollPanel. Я почти уверен, что вам придется сделать это таким образом, чтобы использовать определенные protected методы, такие как ScrollToControl(), который возвращает Point (используется ScrollIntoView).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...