我是原型(Windows 10通用应用程序)UI,并建立了一个非常简单/粗糙的用户控制作为一个"徽章",即在一个圆圈中显示一个数值,并动画值的变化。我的问题是,如果在应用程序页面中只有一个实例,该控件就可以工作。如果有多个实例(即使其他实例是不可见的),那么只有最后一个声明的实例有动画。
我已经尝试在用户控件的XAML中声明动画,并在后面的代码中尝试确保没有交叉/混合正在共享的动画。我还为正在动画的属性添加了一个更改回调,它使用Debug.WriteLine将属性值写出来。对于正确动画的控件实例,值会按预期变化,即如果我们从10到20,则属性设置为10,11,12,13 ....20.对于不工作的实例,每次都将值设置为from属性,即10,10,10,10,10。
下面是用户控件的示例,然后是使用它的三个实例的示例页面。放置这两个问题的是一个名为App3的新的Windows 10通用应用程序,它应该会重现这个问题。在示例页面中,当按钮被点击时,前两个徽章不能正确地显示动画,但最后一个可以。
有人能指出我做错了什么,为什么这打破了一个页面上的多个实例?
谢谢。
注意:代码已经变得相当粗糙,因为我已经hack了周围的东西,试图找出问题是什么,它只是原型代码开始,所以我为混乱道歉。
<UserControl
x:Class="App3.BadgeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App3"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="20"
d:DesignWidth="20">
<Grid>
<Ellipse x:Name="Border" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="{Binding BadgeBorderBrush}" />
<Ellipse x:Name="BadgeInner" Margin="2" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Fill="{Binding BadgeFillBrush}" />
<TextBlock x:Name="BadgeValue" Margin="5" HorizontalAlignment="Center" FontSize="10" VerticalAlignment="Center" TextAlignment="Center" TextTrimming="CharacterEllipsis" Foreground="White" Text="{Binding DisplayValue}" />
</Grid>
public sealed partial class BadgeView : UserControl
{
public DependencyProperty BadgeBorderBrushProperty = DependencyProperty.Register("BadgeBorderBrush", typeof(Brush), typeof(BadgeView), new PropertyMetadata(new SolidColorBrush(Windows.UI.Colors.Yellow)));
public DependencyProperty BadgeFillBrushProperty = DependencyProperty.Register("BadgeFillBrush", typeof(Brush), typeof(BadgeView), new PropertyMetadata(new SolidColorBrush(Windows.UI.Colors.Orange)));
public DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(int), typeof(BadgeView), new PropertyMetadata(0, new PropertyChangedCallback(ValueChanged)));
public DependencyProperty DisplayValueProperty = DependencyProperty.Register("DisplayValue", typeof(int), typeof(BadgeView), new PropertyMetadata(0, DisplayValueChanged));
private static void DisplayValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
System.Diagnostics.Debug.WriteLine(((BadgeView)d).DisplayValue);
}
private Storyboard AnimateBadgeValueCount;
private DoubleAnimation BadgeValueAnimation;
public BadgeView()
{
this.InitializeComponent();
this.BadgeValue.DataContext = this.BadgeInner.DataContext = this.Border.DataContext = this;
AnimateBadgeValueCount = new Storyboard(); ;
AnimateBadgeValueCount.Duration = TimeSpan.FromSeconds(0.5);
Storyboard.AllowDependentAnimations = true;
BadgeValueAnimation = new DoubleAnimation();
BadgeValueAnimation.Duration = TimeSpan.FromSeconds(0.5);
BadgeValueAnimation.EnableDependentAnimation = true;
BadgeValueAnimation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
this.AnimateBadgeValueCount.FillBehavior = FillBehavior.Stop;
this.BadgeValueAnimation.FillBehavior = FillBehavior.Stop;
AnimateBadgeValueCount.Children.Add(BadgeValueAnimation);
Storyboard.SetTarget(AnimateBadgeValueCount, this);
Storyboard.SetTargetProperty(AnimateBadgeValueCount, "DisplayValue");
this.AnimateBadgeValueCount.Completed += AnimateBadgeValueCount_Completed;
}
private void AnimateBadgeValueCount_Completed(object sender, object e)
{
this.DisplayValue = this.Value;
}
private static void ValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var badgeView = (BadgeView)d;
badgeView.AnimateValue();
}
private void AnimateValue()
{
if (Value != DisplayValue)
{
this.BadgeValue.DataContext = this.BadgeInner.DataContext = this.Border.DataContext = this;
this.AnimateBadgeValueCount.Stop();
this.BadgeValueAnimation.From = this.DisplayValue;
this.BadgeValueAnimation.To = this.Value;
this.BadgeValueAnimation.FillBehavior = FillBehavior.Stop;
//Storyboard.SetTarget(this.AnimateBadgeValueCount, this);
//Storyboard.SetTargetProperty(this.AnimateBadgeValueCount, "DisplayValue");
this.AnimateBadgeValueCount.Begin();
}
}
public Brush BadgeBorderBrush
{
get { return (Brush)this.GetValue(this.BadgeBorderBrushProperty); }
set
{
this.SetValue(this.BadgeBorderBrushProperty, value);
}
}
public Brush BadgeFillBrush
{
get { return (Brush)this.GetValue(this.BadgeFillBrushProperty); }
set
{
this.SetValue(this.BadgeFillBrushProperty, value);
}
}
public int Value
{
get { return (int)this.GetValue(ValueProperty); }
set
{
this.SetValue(ValueProperty, value);
}
}
public int DisplayValue
{
get { return (int)this.GetValue(DisplayValueProperty); }
set
{
this.SetValue(DisplayValueProperty, value);
}
}
}
<Page
x:Class="App3.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App3"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<StackPanel Orientation="Vertical">
<Button Content="Do it" x:Name="DoIt1" Click="DoIt1_Click" />
<local:BadgeView x:Name="Badge1" Width="20" Height="20" BadgeFillBrush="Blue" />
<Button Content="Do it" x:Name="DoIt2" Click="DoIt2_Click" />
<local:BadgeView x:Name="Badge2" Width="20" Height="20" />
<Button Content="Do it" x:Name="DoIt3" Click="DoIt3_Click" />
<local:BadgeView x:Name="Badge3" Width="20" Height="20" />
</StackPanel>
public sealed partial class MainPage : Page
{
public MainPage()
{
this.InitializeComponent();
}
private void DoIt1_Click(object sender, RoutedEventArgs e)
{
this.Badge1.Value += 10;
}
private void DoIt2_Click(object sender, RoutedEventArgs e)
{
this.Badge2.Value += 10;
}
private void DoIt3_Click(object sender, RoutedEventArgs e)
{
this.Badge3.Value += 10;
}
}
我所做的就是简化代码,简化并将数据上下文移动到构造函数中加载的事件中:
this.Loaded += (s, e) =>
{
this.DataContext = this;
AnimateBadgeValueCount = new Storyboard(); ;
AnimateBadgeValueCount.Duration = TimeSpan.FromSeconds(0.5);
BadgeValueAnimation = new DoubleAnimation();
BadgeValueAnimation.Duration = TimeSpan.FromSeconds(0.5);
//BadgeValueAnimation.EasingFunction = new CubicEase() { EasingMode = EasingMode.EaseOut };
AnimateBadgeValueCount.Children.Add(BadgeValueAnimation);
Storyboard.SetTarget(AnimateBadgeValueCount, this);
Storyboard.SetTargetProperty(AnimateBadgeValueCount, "DisplayValue");
this.AnimateBadgeValueCount.Completed += AnimateBadgeValueCount_Completed;
};
private async void AnimateValue()
{
if (Value != DisplayValue)
{
this.AnimateBadgeValueCount.Stop();
this.BadgeValueAnimation.From = this.DisplayValue;
this.BadgeValueAnimation.To = this.Value;
BadgeValueAnimation.EnableDependentAnimation = true;
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.High, () =>
{
this.AnimateBadgeValueCount.Begin();
});
}
}
我已经评论了EasingFunction,它可以工作,但在我看来更适合。这很奇怪,因为如果我只在构造函数中设置数据上下文,它就不能正常工作,但在构造函数中却可以正常工作。