wpf - 停止 wpf 动画失败并出现 InvalidCastException
问题描述
我有一些显示 int 值的骰子,我正在尝试为它们设置动画,同时等待显示新的随机整数。我有一个可观察的 DieViewModel 集合和一个数据模板来可视化它们。当我开始掷骰子(以编程方式)时,我将 DieViewModels 上的“IsRolling”属性设置为 true,这会触发动画。动画快速切换骰子值。到这里为止它工作得很好。
当我获得骰子的新值时,我清除集合并添加新的 DieViewModels。然后我触发 PropertyChangedEvent 来告诉视图发生了一些变化。在这一点上,我得到了一个 InvalidCastException。没有动画它工作得很好。如果我为除(绑定)值之外的任何其他属性设置动画,它就可以正常工作。
我找到了解决方法,但我不明白这个问题。如果我不清除 oberservable 集合,保留旧的 DieViewModels 并将所有属性设置为新的 DieViewModels,它可以工作。但是从另一个列表更新列表元素的代码非常难看。而且我仍然需要 Dice.AddRange 部分来初始化列表,但必须确保它只运行一次。...除了新的 diceList 包含的元素比旧的多...我不喜欢这个解决方案
数据模板:
<DataTemplate x:Key="DieTemplate" DataType="gameElements:DieViewModel">
<Button>
<Label x:Name="NumberLabel"
Content="{Binding Value}"/>
</Button>
<DataTemplate.Resources>
<Storyboard x:Key="DieRollingAnimation">
<Int32Animation Storyboard.TargetName="NumberLabel"
Storyboard.TargetProperty="Content"
From="1" To="6" Duration="0:0:0.6"
RepeatBehavior="Forever"/>
</Storyboard>
</DataTemplate.Resources>
<DataTemplate.Triggers>
<DataTrigger Binding="{Binding IsRolling}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard
x:Name="beginAnimation"
Storyboard="{StaticResource DieRollingAnimation}" />
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<StopStoryboard
BeginStoryboardName="beginAnimation" />
</DataTrigger.ExitActions>
</DataTrigger>
</DataTemplate.Triggers>
</DataTemplate>
调用更新骰子集合的方法:
private void UpdateDice(IEnumerable<DieViewModel> newDice)
{
Dice.Clear();
Dice.AddRange(newDice);
RaisePropertyChanged(nameof(Dice));
}
我试图在重新初始化列表之前停止动画:
private void UpdateDice(IEnumerable<DieViewModel> newDice)
{
for (int i = 0; i < Dice.Count; i++)
{
Dice[i].IsRolling = false;
}
Dice.Clear();
Dice.AddRange(newDice);
RaisePropertyChanged(nameof(Dice));
}
动画停止,但是当我提出 PropertyChanged 时问题仍然存在。
我已经好几年没有写过 for 循环了,我认为这不是 2020 年的 c# 风格。因此,如果我的问题没有其他解决方案,至少有人可以告诉我是否有办法使用 LINQ 实现这一目标?
这应该至少是一个 LINQ 工作:
if (Dice.Count > 0 && Dice.Count == newDice.Count)
{
for (int i = 0; i < Dice.Count; i++)
{
Dice[i].IsRolling = false;
Dice[i].Value = newDice[i].Value;
// update some more properties
}
}
解决方案
Storyboard
在清除集合之前,您必须通过设置IsRolling
为 来停止false
。Storyboard
仍然绑定到项目的属性IsRolling
。
for 循环的 LINQ 变体(需要参考System.ValueTuple
):
Dice.Take(Dice.Count)
.Zip(newDice.Take(Dice.Count), (oldDice, newDice) => (oldDice, newDice)
.ToList()
.ForEach(dicePair =>
{
dicePair.oldDice.IsRolling = false;
dicePair.oldDice.Value = dicePair.newDice.Value;
});
for 循环仍然有效"2020 c# style"。在大多数情况下,它的性能要好得多。
推荐阅读
- reactjs - 单击删除按钮时,使用 Reactjs Table 行不会被删除
- python - python中的条件分组
- python - Discord.py 排行榜命令不起作用
- arrays - Pyspark 展平数组并分解结构以获得所需的输出
- javascript - 带有反应钩子的单元测试失败
- java - 如何跳过或删除 EntityExistsException 的原因?
- sql - SQL Server 阻塞链
- python - Debian10 python3问题
- java - Android Studio - setQuery 在第一次搜索时不起作用
- html - 如何使用 python (python -m http.server) 在本地服务器上打开 html 文件?