我创建了一个名为“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事件,其中I:
看起来像这样:
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();
}
由于一些奇怪的原因,从故事板内部完成事件调用ProcessQueue似乎打破了故事板。但只有在执行了正确的淡化序列时才会执行。
如果我从索引0淡入1然后快速回到0,则淡入淡出停止工作。它必须足够快,以便在第一次淡入淡出时尝试淡入0(因此将其置于队列中)。
在我正在使用ControlFader的窗口中,为了触发淡入淡出,我将绑定到ControlFader的SelectedIndex。从索引0到1的淡入之后,绑定停止更新,然后再返回到0。
当我删除对ProcessQueue的调用时,动画和绑定永远不会中断,但我的淡入淡出不同步(它们落后),因为队列没有被处理,所以当前的SelectedIndex应该是什么。
我很难过。有什么建议吗?
答案 0 :(得分:1)
我的ProcessQueue方法的最后一行是问题:
SelectedIndex = itemIndex;
因为我在SelectedIndex上设置了一个绑定,通过在控件代码中分配它,我的绑定被删除了。由于这是在ProcessQueue方法中,因此只有在排队项目时才会出现问题。
我通过使用所选项目来修复它:
SelectedItem = nextItem;
由于我从未在SelectedItem上设置任何绑定表达式,因此永远不会遇到错误。