使用Silverlight DispatcherTimer - 有更好的方法(动画上的DependencyProperty)吗?

Con*_*dev 4 silverlight animation

我正在制作地图上的"种族"动画.比赛需要45分钟,但动画运行60秒.

您可以观看2008 City2Surf比赛演示,了解我的意思.

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

我想也许动画上有DependencyProperty而不仅仅是StoryBoard.GetCurrentTime(),但我必须这样做

         // 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();
Run Code Online (Sandbox Code Playgroud)

然后是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();
    }
Run Code Online (Sandbox Code Playgroud)

这有效并且似乎表现良好 - 但我的问题是:我是否在Silverlight动画/故事板课程中遗漏了一些能够更加整洁地完成此操作的内容?我必须记得也要停止 DispatcherTimer!

或者用另一种方式提出问题:关于TextBox内容"动画"的更好的建议(.Text本身,而不是位置/尺寸/等)?

pto*_*son 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
}
Run Code Online (Sandbox Code Playgroud)

然后你可能有一个格式转换器:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

我差点忘了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;
    }
}
Run Code Online (Sandbox Code Playgroud)

所有这些东西都可以重复使用,并且应该存在于您的工具箱中.我把它拉出来了.然后,当然,你把它们连在一起:

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();
Run Code Online (Sandbox Code Playgroud)

这应该可以解决问题.这只是一百万行代码.我们甚至还没有编写Hello World ...;)我没有编译它,但我直接从我的库中复制并粘贴了3个类.我已经使用了很多.它很棒.我也将这些类用于其他事情.TickFormatConverter在数据绑定时派上用场.我也有一个做秒.很有用.DoubleTextblockSetter允许我为数字设置动画,这非常有趣.特别是当您应用不同类型的插值时.

请享用.