我正在制作地图上的“种族”动画。比赛需要45分钟,但动画运行60秒。
您可以观看2008 City2Surf race demo以了解我的意思。
左上角的“比赛时钟”必须显示“实时”,并且必须在.xaml.cs
中设置System.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();
然后是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 :(得分: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允许我为数字设置动画,这非常有趣。特别是在应用不同类型的插值时。
享受。