2008-10-06 159 views
2

我有一个控件动态添加到面板的窗体。但是,当它们这样做时,它们会多次添加到折叠下方(容器的底部)。很高兴.NET Framework提供了这个ScrollControlIntoView方法,但是,为了增加可用性,如果有一种简单的动画方法,以便用户很容易理解Panel自动滚动,这也会很不错。有没有简单的方法来动画ScrollableControl.ScrollControlIntoView方法?

有没有人遇到过这个问题,或者对于如何解决它有什么想法?

回答

1

您可以子类Panel,添加Timer,并覆盖ScrollIntoView(),以便在新的AnimatedScrollPanel中执行此操作。我很肯定你必须这样做才能使用某些protected方法,例如ScrollToControl(),它会返回Point(由ScrollIntoView使用)。

1

@Joel

谢谢!我明白了,用反射镜的帮助并不难。可能有方法来优化它,但这是我必须开始的。恰巧我需要FlowLayoutPanel中的这个功能,但它可以处理从ScrollableControl继承的任何东西。

编辑:我改变了一些东西,由于@Joel B指出我没有删除委托,保持定时器对象无限期。我相信我通过将委托分配给一个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 }); 
    } 
} 
+0

有一个大问题。您不断将代理添加到Tick事件中,并且在完成时不要删除它。您需要重新设计一下,以便您一次只能在Tick事件中拥有1个代表。 – 2008-10-07 14:58:21

相关问题