2009-06-14 85 views
4

我在地图上为'比赛'制作动画。比赛需要45分钟,但动画运行60秒。使用Silverlight的DispatcherTimer - 有没有更好的方法(动画DependencyProperty)?

你可以看2008 City2Surf race demo看看我的意思。

在左上角的“种族时钟”必须显示“实时”,并且必须是建立在.xaml.csSystem.Windows.Threading.DispatcherTimer似乎有点一个黑客攻击的。

我想也许有会是上的动画,而不是仅仅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(); 

然后Tick事件处理

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(); 
    } 

这工作和似乎表现良好 - 但我的问题是:我是否在Silverlight动画/故事板类中丢失了一些可以更加整洁的东西?我必须记得停止的DispatcherTimer呢!

或者以另一种方式提出问题:对TextBox内容(.Text本身,而不是位置/尺寸/等)的“动画”有什么更好的建议?

+0

我喜欢比赛的形象化。做得好。 – caryden 2009-08-04 19:05:48

回答

5

这是一种方法。这很好,很简单,但有点混乱。你可以摆脱故事板,并在每个滴答,增加一个本地值的滴答间隔,并用它来设置你的时间。你将只有一个时间片。

或...更优雅和可重用的方法是创建一个辅助类,它是一个DependencyObject。我还会使用一个带有DoubleAnimation的StoryBoard,并将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 2009-06-18 10:13:11

相关问题