2011-12-16 2 views
0

"ControlFader"というカスタムコントロールを作成しました。セレクタプリミティブから継承します。コントロールに追加された項目は、重複するコントロールとして単一のグリッドに配置されます。目的は、選択されたアイテムがフェードインし、以前に選択されたアイテムがフェードアウトするアニメーションを持つことです。キューを介したコントロールのアニメーション化とアニメーション化

まず、不透明度がゼロに設定されたカスタムアイテムコンテナ(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; 
} 

Iは次色あせすべき項目を示すためにキューを追加しました。アイテムは、このメソッドを使用してキューから削除されています

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イベント上書き:

  1. チェックそれは
  2. であればフェードが既にアイテムが起こって、キューされている場合は、フェードを開始

それは次のようになります。

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

'ListBoxItem'は' Selected'と 'Unselected'ビジュアルステートを持っていますが、なぜそれらを使わないのですか? –

+0

@Xin興味深い提案ですが、状態アニメーションの1つが行われている場合、どのようにして次のアイテムを追加するのを防ぐことができますか? – mbursill

+0

状態アニメーション中に選択を無効にするのはどうですか? –

答えて

1

私ProcessQueueメソッドの最後の行は問題だった:

SelectedIndex = itemIndex; 

私はセットアップ私は、バインディング、コントロールコード内でそれを割り当てることで、SelectedIndexを上結合が削除されていた持っていたので。これはProcessQueueメソッドの中にあったので、キューに入れられたアイテムがあるときに問題が発生し始めました。

私が代わりに選択した項目を使って、それを修正:私はのSelectedItem上の任意のバインディング式を設定したことがないので

SelectedItem = nextItem; 

、バグがヒットされることはありません。

関連する問題