2008-10-06 6 views
2

컨트롤이 패널에 동적으로 추가되는 양식이 있습니다. 그러나 그렇게하면 접을 부분 아래쪽에 여러 번 추가됩니다 (컨테이너 하단). .NET Framework가이 ScrollControlIntoView 메서드를 제공한다는 것은 좋은 일입니다. 그러나 사용자 편의성을 높이기 위해 쉽게 애니메이션을 적용 할 수 있다면 Panel이 자동으로 스크롤된다는 것을 사용자가 쉽게 이해할 수 있습니다.ScrollableControl.ScrollControlIntoView 메서드에 애니메이션을 적용하는 쉬운 방법이 있습니까?

아무도이 문제가 발생하거나 문제를 해결할 방법이 있습니까?

답변

1

Panel의 하위 클래스를 추가하고 Timer을 추가 한 다음 을 재정 의하여 새로운 AnimatedScrollPanel에서이 작업을 수행 할 수 있습니다. ScrollToControl()과 같이 특정 protected 메서드를 사용하려면 Point (ScrollIntoView에서 사용)을 반환해야합니다.

1

@ 조엘

고마워요! 나는 그것을 가지고있다, 반사체로부터의 작은 도움과 함께하기가 그렇게 어렵지 않았다. 최적화 할 수있는 방법이있을 수 있지만 이것이 내가 시작해야 할 것입니다. 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 }); 
    } 
} 
+0

큰 문제가 하나 있습니다. 델리게이트를 틱 이벤트에 계속 추가하고 작업이 끝나면 제거하지 마십시오. 한 번에 Tick 이벤트에서 1 명의 대리인 만 가질 수 있도록 약간의 재 설계가 필요합니다. –

+0

이러한 재 설계에는 아마도 익명의 대리인을 사용하지 않아도됩니다. 이벤트에서 익명의 대리자를 제거 할 수 없습니다. –

+0

의견을 보내 주셔서 감사합니다. 나는 확실히 이해하고 있는지 잘 모르겠다. 만약 익명의 위임자를 사용하지 않는 것으로 변경했다면 위임자를 추가하는 코드는 다음과 같다. timer.Tick + = 새로운 EventHandler (timer_Tick) 이벤트에서 대의원을 제거해야합니까? –

관련 문제