2009-06-14 3 views
4

지도에서 '레이스'에 애니메이션을 적용하고 있습니다. 경주에는 45 분이 걸리지 만 애니메이션은 60 초 동안 실행됩니다.Silverlight 사용 DispatcherTimer - 더 좋은 방법이 있습니까 (Animation의 DependencyProperty)?

2008 City2Surf race demo을 시청하면 어떤 의미인지 알 수 있습니다.

왼쪽 상단에있는 '인종 시계'

는 "실시간"를 보여주고, 가지고 있어야 해킹의 비트를 보이는 System.Windows.Threading.DispatcherTimer.xaml.cs의 수 설정에.

나는 어쩌면이 아니라 단지 StoryBoard.GetCurrentTime()보다 애니메이션에 DependencyProperty에있을 거라고 생각하지만, 대신에 나는

  // SET UP AND START TIMER, before StoryBoard.Begin() 
     dt = new System.Windows.Threading.DispatcherTimer(); 
     dt.Interval = new TimeSpan(0, 0, 0, 0, 100); // 0.1 second 
     dt.Tick +=new EventHandler(dt_Tick); 
     winTimeRatio = (realWinTime.TotalSeconds * 1.0)/animWinTime.TotalSeconds; 
     dt.Start(); 

다음

void dt_Tick(object sender, EventArgs e) 
    { 
     var sb = LayoutRoot.Resources["Timeline"] as Storyboard; 
     TimeSpan ts = sb.GetCurrentTime(); 
     TimeSpan toDisplay = new TimeSpan(0,0, 
       Convert.ToInt32(ts.TotalSeconds * winTimeRatio)); 
     RaceTimeText.Text = toDisplay.ToString(); 
    } 

이것은 작동 Tick 이벤트 핸들러에 있었다 확인을 수행하는 것 같다 -하지만 내 질문은 : 내가 깔끔하게이 일을 할 것이라고 Silverlight 애니메이션/스토리 보드 클래스에서 뭔가를 놓친 건가요? 나는 을 기억해야한다. DispatcherTimer도 중지해야한다!

다른 방법으로 질문을 올리면 TextBox 콘텐츠의 '애니메이션'에 대한 더 좋은 제안 (.Text 자체, 위치/크기/기타가 아님)?

+0

나는 경주의 시각화를 아주 좋아했습니다. 잘 했어. – caryden

답변

5

그건 한 가지 방법입니다. 멋지고 단순하지만 약간 지저분합니다. 스토리 보드를 제거하고 각 틱마다 틱 간격으로 로컬 값을 증가시키고이를 사용하여 시간을 설정할 수 있습니다. 그런 다음 한 번만 시간 조각을 갖습니다.

또는 ... 더 우아하고 재사용 가능한 방법은 DependencyObject 인 도우미 클래스를 만드는 것입니다. Storyboard를 DoubleAnimation과 함께 사용하면 Storyboard.Target을 DoubleTextblockSetter의 인스턴스에 바인딩 할 수 있습니다. 스토리 보드 기간을 시간으로 설정하고 값을 초 단위로 설정하십시오. 다음은 DoublerBlockSetterCode입니다.

public class DoubleTextBlockSetter : DependencyObject 
{ 
    private TextBlock textBlock { get; private set; } 
    private IValueConverter converter { get; private set; } 
    private object converterParameter { get; private set; } 

    public DoubleTextBlockSetter(
       TextBlock textBlock, 
       IValueConverter converter, 
       object converterParameter) 
    { 
     this.textBlock = textBlock; 
     this.converter = converter; 
     this.converterParameter = converterParameter; 
    } 

    #region Value 

    public static readonly DependencyProperty ValueProperty = 
     DependencyProperty.Register(
      "Value", 
      typeof(double), 
      typeof(DoubleTextBlockSetter), 
      new PropertyMetadata(
       new PropertyChangedCallback(
        DoubleTextBlockSetter.ValuePropertyChanged 
       ) 
      ) 
     ); 

    private static void ValuePropertyChanged(
     DependencyObject obj, 
     DependencyPropertyChangedEventArgs args) 
    { 
     DoubleTextBlockSetter control = obj as DoubleTextBlockSetter; 
     if (control != null) 
     { 
      control.OnValuePropertyChanged(); 
     } 
    } 

    public double Value 
    { 
     get { return (double)this.GetValue(DoubleTextBlockSetter.ValueProperty); } 
     set { base.SetValue(DoubleTextBlockSetter.ValueProperty, value); } 
    } 

    protected virtual void OnValuePropertyChanged() 
    { 
     this.textBlock.Text = this.converter.Convert(
      this.Value, 
      typeof(string), 
      this.converterParameter, 
      CultureInfo.CurrentCulture) as string; 
    } 

    #endregion 
} 

그런 다음 당신은 포맷 컨버터가있을 수 있습니다 :

public class TicksFormatConverter : IValueConverter 
{ 
    TimeSpanFormatProvider formatProvider = new TimeSpanFormatProvider(); 

    public object Convert(object value, 
     Type targetType, 
     object parameter, 
     CultureInfo culture) 
    { 
     long numericValue = 0; 

     if (value is int) 
     { 
      numericValue = (long)(int)value; 
     } 
     else if (value is long) 
     { 
      numericValue = (long)value; 
     } 
     else if (value is double) 
     { 
      numericValue = (long)(double)value; 
     } 
     else 
      throw new ArgumentException("Expecting type of int, long, or double."); 

     string formatterString = null; 
     if (parameter != null) 
     { 
      formatterString = parameter.ToString(); 
     } 
     else 
     { 
      formatterString = "{0:H:m:ss}"; 
     } 

     TimeSpan timespan = new TimeSpan(numericValue); 

     return string.Format(this.formatProvider, formatterString, timespan); 
    } 

    public object ConvertBack(
     object value, 
     Type targetType, 
     object parameter, 
     CultureInfo culture) 
    { 
     throw new NotImplementedException(); 
    } 
} 

나는 거의 TimespanFormatProvider를 잊어 버렸습니다. Silverlight에는 시간 범위에 대한 형식 공급자가 없으므로 나타납니다.

public class TimeSpanFormatProvider : IFormatProvider, ICustomFormatter 
{ 
    public object GetFormat(Type formatType) 
    { 
     if (formatType != typeof(ICustomFormatter)) 
      return null; 
     return this; 
    } 

    public string Format(string format, object arg, IFormatProvider formatProvider) 
    { 
     string formattedString; 

     if (arg is TimeSpan) 
     { 
      TimeSpan ts = (TimeSpan)arg; 
      DateTime dt = DateTime.MinValue.Add(ts); 
      if (ts < TimeSpan.FromDays(1)) 
      { 
       format = format.Replace("d.", ""); 
       format = format.Replace("d", ""); 
      } 

      if (ts < TimeSpan.FromHours(1)) 
      { 
       format = format.Replace("H:", ""); 
       format = format.Replace("H", ""); 
       format = format.Replace("h:", ""); 
       format = format.Replace("h", ""); 
      } 

      // Uncomment of you want to minutes to disappear below 60 seconds. 
      //if (ts < TimeSpan.FromMinutes(1)) 
      //{ 
      // format = format.Replace("m:", ""); 
      // format = format.Replace("m", ""); 
      //} 

      if (string.IsNullOrEmpty(format)) 
      { 
       formattedString = string.Empty; 
      } 
      else 
      { 
       formattedString = dt.ToString(format, formatProvider); 
      } 
     } 
     else 
      throw new ArgumentNullException(); 

     return formattedString; 
    } 
} 

모든 것들은 재사용이 가능하며 도구 상자에 있어야합니다. 나는 그것을 내 것으로부터 끌어 냈다. 그런 다음 물론 모두 연결합니다.

Storyboard sb = new Storyboard(); 
DoubleAnimation da = new DoubleAnimation(); 
sb.Children.Add(da); 
DoubleTextBlockSetter textBlockSetter = new DoubleTextBlockSetter(
    Your_TextBlock, 
    new TicksFormatConverter(), 
    "{0:m:ss}"); // DateTime format 

Storyboard.SetTarget(da, textBlockSetter); 

da.From = Your_RefreshInterval_Secs * TimeSpan.TicksPerSecond; 
da.Duration = new Duration(
    new TimeSpan(
     Your_RefreshInterval_Secs * TimeSpan.TicksPerSecond)); 
sb.begin(); 

그리고 그 트릭을 수행해야합니다. 이는 단지 백만 줄의 코드와 같습니다. 그리고 Hello World는 아직 작성하지 않았습니다 ...;) 나는 컴파일하지 않았지만, 3 개의 클래스를 직접 내 라이브러리에서 복사하여 붙여 넣기했습니다. 나는 그들을 많이 사용했다. 그것은 위대한 작품. 나는 또한 다른 것들을 위해 그 수업들을 사용한다. TickFormatConverter는 데이터 바인딩시 편리합니다. 나는 또한 초를하는 사람이있다. 굉장히 유용하다. DoubleTextblockSetter를 사용하면 정말 재미있는 숫자로 애니메이션을 만들 수 있습니다. 특히 다른 유형의 보간을 적용 할 때.

즐기십시오.

+0

와우 매우 포괄적 인 답변! 나는 그것을 시도하고 내가 어떻게 가는지 볼 것이다 ... – Conceptdev

관련 문제