使用Silverlight DispatcherTimer - 有没有更好的办法(上的DependencyProperty动画)? [英] Using Silverlight DispatcherTimer - is there a better way (DependencyProperty on Animation)?

查看:258
本文介绍了使用Silverlight DispatcherTimer - 有没有更好的办法(上的DependencyProperty动画)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在一个动画在地图上的种族。这场比赛需要45分钟,但动画60秒运行。

I'm animating a 'race' on a map. The race takes 45 minutes, but the animation runs for 60 seconds.

您可以观看 2008年城市到海滩马拉松大赛竞赛演示要明白我的意思。

You can watch the 2008 City2Surf race demo to see what I mean.

在左上角的种族时钟'必须显示实时,并且必须是建立在 .xaml.cs System.Windows.Threading.DispatcherTimer 其中似乎有点一个黑客攻击

The 'race clock' in the top-left must show "real time", and had to be set-up in the .xaml.cs with a System.Windows.Threading.DispatcherTimer which seems a bit of a hack.

我想也许有会是在动画,而不仅仅是 StoryBoard.GetCurrentTime(),而是我不得不

I thought maybe there'd be a DependencyProperty on the animation rather than just StoryBoard.GetCurrentTime(), but instead I have had to

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

这可行,似乎工作正常 - 但是我的问题是:我失去了在Silverlight动画/故事板类的东西,会做这更加整齐?我记得的停止的的DispatcherTimer呢!

This works and seems to perform OK - but my question is: am I missing something in the Silverlight animation/storyboard classes that would do this more neatly? I have to remember to stop the DispatcherTimer too!

还是要提出这个问题的另一种方式:在文本框的动画什么更好的建议的内容(。文本本身,而不是位置/尺寸/等)?

Or to put the question another way: any better suggestions on 'animation' of TextBox content (the .Text itself, not the location/dimensions/etc)?

推荐答案

这是一种方法。这是很好的,简单的,但有点凌乱。你可以摆脱故事板,并在每个tick,通过增加了时间间隔,并用它来设置你的时间局部值。那么你就只能有一个时间片。

That is one way. It's nice and simple, but a bit messy. You could get rid of the storyboard and on each tick, increment a local value by the tick interval and use that to set your time. You would then only have one time piece.

或者...更优雅和可重复使用的方法是创建一个辅助类这是一个DependencyObject的。我也只是用故事板带DoubleAnimation是一个绑定的Storyboard.Target到DoubleTextblockSetter的一个实例。将故事板持续时间你的时间和值设置为你的时间,以秒。这里是DoublerBlockSetter code。

Or... A more elegant and re-usable way would be to create a helper class that is a DependencyObject. I would also just use a StoryBoard with a DoubleAnimation an bind the Storyboard.Target to an instance of the DoubleTextblockSetter. Set the storyboard Duration to your time and set the value to your time in seconds. Here is the 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
}

这时,你可能有一个格式转换器:

Then you might have a format converter:

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时间跨度无格式提供,所以才出现。

I almost forgot the TimespanFormatProvider. There is no format provider for timespan in Silverlight, so it appears.

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

所有的东西是可以重复使用,应该住在你的工具箱。我从我把它。然后,当然,你线它一起:

All that stuff is re-usable and should live in your tool box. I pulled it from mine. Then, of course, you wire it all together:

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

和应该做的伎俩。一个它只是像一百万行code的。而我们甚至还没有编写的Hello World只是还没有...;)我没有编译,但我没有复制和3类直接从我的图书馆里的浆糊。我用他们不少。它的伟大工程。我还使用这些类的其他事情。该TickFormatConverter就派上用场了数据绑定时。我也有一个没有秒。很有用。该DoubleTextblockSetter让我的动画数字,这是很有趣的。尤其是当你应用不同类型的插值。

And that should do the trick. An it's only like a million lines of code. And we haven't even written Hello World just yet...;) I didn't compile that, but I did Copy and Paste the 3 classes directly from my library. I've used them quite a lot. It works great. I also use those classes for other things. The TickFormatConverter comes in handy when data binding. I also have one that does Seconds. Very useful. The DoubleTextblockSetter allows me to animate numbers, which is really fun. Especially when you apply different types of interpolation.

享受。

这篇关于使用Silverlight DispatcherTimer - 有没有更好的办法(上的DependencyProperty动画)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆