通过队列动画和重新动画控件
本文关键字:动画 控件 新动画 队列 | 更新日期: 2023-09-27 18:18:18
我创建了一个自定义控件ControlFader。它继承自Selector原语。添加到控件中的项作为重叠控件放置到单个网格中。我们的目标是有一个动画,其中选择的项目是淡入的,而以前选择的项目是淡入的。
首先,我提供了一个自定义项目容器(类型为ControlFaderItem),其不透明度设置为零。下面的代码用于创建故事板(FadeTime在别处定义):
private Storyboard CreateStoryboard(ControlFaderItem sourceItem, ControlFaderItem targetItem)
{
var fadeControlsStoryboard = new Storyboard();
if (sourceItem != null)
{
var sourceAnimation = new DoubleAnimation(1, 0, FadeTime);
sourceAnimation.SetValue(Storyboard.TargetProperty, sourceItem);
sourceAnimation.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(UIElement.OpacityProperty));
fadeControlsStoryboard.Children.Add(sourceAnimation);
}
if (targetItem != null)
{
var targetAnimation = new DoubleAnimation(0, 1, FadeTime);
targetAnimation.SetValue(Storyboard.TargetProperty, targetItem);
targetAnimation.SetValue(Storyboard.TargetPropertyProperty, new PropertyPath(UIElement.OpacityProperty));
fadeControlsStoryboard.Children.Add(targetAnimation);
}
return fadeControlsStoryboard;
}
我添加了一个队列来指示下一个要褪色的项目。使用以下方法从队列中删除项:
private void ProcessQueue()
{
if (isFadeAnimating)
return;
// can't process if there are no queued items
if (FadeQueue.Count == 0)
return;
// get the next item to fade to
var nextItem = FadeQueue.Dequeue();
// locate the index of the item
var itemIndex = Items.IndexOf(nextItem);
if (itemIndex != -1)
SelectedIndex = itemIndex;
}
我重写OnSelectionChanged事件,其中我:
- 检查淡出是否已经发生,如果是 ,则队列项。
- 开始淡出
它看起来像这样:
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
// code to simulate an OnSelectionChanging is here (removed for brevity)
// it's used to queue a new selection if isFadeAnimating is true, and reverse the selection
// code to obtain source and target container item also removed for brevity
if (isFadeAnimating)
return;
isFadeAnimating = true;
var storyboard = CreateStoryboard(sourceItem, targetItem);
storyboard.Completed += (s, arg) =>
{
if (sourceItem != null)
sourceItem.Opacity = 0d;
isFadeAnimating = false;
base.OnSelectionChanged(e);
ProcessQueue();
};
storyboard.Begin();
}
由于一些奇怪的原因,从storyboard完成事件内部调用ProcessQueue似乎破坏了storyboard。但前提是执行了正确的淡出顺序。
如果我从索引0淡出到1,然后足够快地回到0,淡出停止工作。它必须足够快,以便在第一次淡出发生时尝试退隐回0(因此将其放在队列中)。
在我使用ControlFader的窗口中,为了触发淡出,我绑定到ControlFader的selecteindex。当索引从0变为1,然后再变为0时,绑定停止更新。
当我移除对ProcessQueue的调用时,动画和绑定永远不会中断,但是我的淡出并不同步(它们落后),因为队列没有被处理,应该是当前的selecteindex。
我难住了。有什么建议吗?
ProcessQueue方法中的最后一行是问题所在:
SelectedIndex = itemIndex;
因为我在SelectedIndex上设置了绑定,通过在控件代码中分配它,我的绑定被删除了。由于这是在ProcessQueue方法中,所以只有当有队列项时才会出现问题。
我用selected item代替
SelectedItem = nextItem;
由于我从未在SelectedItem上设置任何绑定表达式,因此该错误从未被击中。