@Joel
Merci! Je l'ai, n'était pas trop difficile à faire avec un peu d'aide de réflecteur. Il pourrait y avoir des façons de l'optimiser, mais c'est ce que je dois commencer. Il se trouve que j'avais besoin de cette fonctionnalité dans un FlowLayoutPanel, mais cela fonctionnerait avec tout ce qui hérite de ScrollableControl.
Modifier: J'ai changé quelques choses à cause de @Joel B Fant en soulignant que je ne supprimais pas le délégué, en gardant l'objet timer indéfiniment. Je crois que j'ai allégé cette préoccupation en affectant le délégué à un objet EventHandler afin qu'il puisse être supprimé en lui-même.
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 });
}
}
Il y a un gros problème avec ça. Vous continuez d'ajouter le délégué à l'événement Tick et ne le supprimez jamais lorsque vous avez terminé. Vous devez redessiner un peu afin que vous n'ayez que le délégué 1 dans l'événement Tick à la fois. –
Une telle refonte impliquera probablement de ne pas utiliser un délégué anonyme. Vous ne pouvez pas supprimer un délégué anonyme de l'événement. –
Merci pour vos commentaires. Je ne suis pas sûr que je comprends bien si: si je devais changer pour ne pas utiliser un délégué anonyme mon code pour ajouter le délégué serait quelque chose comme timer.Tick + = new EventHandler (timer_Tick) Où me suggérez-vous besoin de retirer le délégué de l'événement? –