tmytのらくがき

個人の日記レベルです

TransitionFrame+FluidMoveBehavior+ListBox+ObservableCollectionで死ぬことがある

ようするに、表題の組み合わせで例外吐いて死にます。

条件

  1. SilverlightToolkitのTransitionFrameを使う
  2. ListBoxのItemsPanelにFuildMoveBehaviorを付ける
  3. ObservableCollectionをItemsSouceにBindingする
  4. 遷移先でObservableCollectionを書き換えて、戻ってくる

こうすると死にます。ObservableCollection共有しちゃだめですか?

原因としては、TransitionFrameがアニメーションするためにUpdateLayoutを呼んでいて、UpdateLayoutすると、ObservableCollectionが更新されているのでFluidMoveBehaviorがアニメーションしようとするけどVisualTreeの構築が終わっていないので例外吐いて死ぬみたい。

とりあえず回避方法。XAMLでBehaviorを付けない。

  1. LoadedイベントでFluidMoveBehaviorを生成
  2. VisualTreeHelperで必死にたどってListBoxのItemsPanelに追加
  3. OnNavigatingFromでListBoxのItemsPanelからBehaviorを削除

VisualTreeができあがってからBehaviorを付ける。別の画面へ遷移する前にBehaviorを外す。これでわりとどうにかなるみたい。

こんな感じ。

private DependencyObject GetNthChild(DependencyObject dp, int depth)
{
    while (depth > 0)
    {
        dp = VisualTreeHelper.GetChild(dp, 0);
        depth--;
    }
    return dp;
}

private void mainPage_Loaded(object sender, RoutedEventArgs e)
{
    FluidMoveBehavior fluid = new FluidMoveBehavior();
    fluid.AppliesTo = FluidMoveScope.Children;
    fluid.Duration = TimeSpan.FromMilliseconds(300);
    fluid.EaseY = new CircleEase() { EasingMode = EasingMode.EaseInOut };
    Interaction.GetBehaviors(GetNthChild(itemsList, 6)).Add(fluid);
}

protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
{
    Interaction.GetBehaviors(GetNthChild(itemsList, 6)).Clear();
    base.OnNavigatingFrom(e);
}