空談録

世界で5人くらいに役立ちたい

Windows Store Appsで階層式メニューを考えるやつの途中経過

25日だしいったんまとめて終わらないところはあとでやります(どこまでも遅れる

前回の超絶長い記事の続きです。しかし心が折れた
前回の記事→

左側タップで前のペインに戻る

このとき2つのパターンがあります(っていうかVisualState見ればわかる)
TransittedMain→First
TransittedMain→TransittedMain

さて、TransittedMain→TransittedMainはすごい面倒なので先にTransittedMain→Firstの遷移を実装しましょう

その前に左側タップの実装を行います。右側と同じくRectangleを置きます。こんなxaml

<Rectangle Width="100" HorizontalAlignment="Left" Fill="Black" Opacity="0" PointerPressed="MenuBackRectangle_PointerPressed" Name="MenuBackRectangle" Visibility="Collapsed" />

位置としては左側のPastObjectGridの位置に重なるように設置します。Visibilityの初期値はCollapsedでFirstの時に触れないようにします。
TransittedMainの時にVisibility=Visibleで対応してRectangleの実装は完成です。ただ何も反応しないのでMouseHoveredとかのVisualStateを変更するのもいいかなーとも

追加し終えたらxaml.csを変更します
xaml.cs側ではどこに戻せばいいのか取得できないため、現在の遷移回数を内部的に持っておきます
(回数としてますが今回はboolでもいけます)

回数を追加してPointerPressedの中身を編集するとこんな感じ

private int transittedCount = 0;
private bool isBackTransition = false;
internal event Action MenuBack = null;

private void MenuBackRectangle_PointerPressed(object sender, PointerRoutedEventArgs e)
{
    if (isBackTransition)
    {
        return;
    }
    isBackTransition = true;
    if (transittedCount == 1)
    {
        VisualStateManager.GoToState(this, "First", true);
    }
    else
    {
        MenuBack();
    }
}

MenuBackイベントはこんかいの記事では触りませんがまあ一応
transittedCountが1のときはTransittedMain→Firstへの遷移を行うようにして、それ以外のときは別の遷移を行います
いきなりVSMでステート遷移するのはMovingObjectに相当するオブジェクトが不要なので遷移後に後処理を行います

またFirst→TransittedMainの処理に当たるMainObjectGridのDataContextChangedも編集します

private void MainObjectGrid_DataContextChanged(FrameworkElement sender, DataContextChangedEventArgs args)
{
    if (args.NewValue == null)
    {
        isFirstTransition = true;
        transittedCount = 0;
        return;
    }
    if (isFirstTransition)
    {
        isFirstTransition = false;
        transittedCount = 1;
        VisualStateManager.GoToState(this, "TransittedMain", true);
    }
}

args.NewValueがnullだったらFirstの状態と仮定してプロパティの内容もFirstの状態にしておきます
あとは普通に遷移したことをプロパティに記録

続いてStoryboard_Completedを変更します

private void Storyboard_Completed(object sender, object e)
{
    if (isTransitting)
    {
        isTransitting = false;
        VisualStateManager.GoToState(this, "TransittedMain", true);
        MainPane_MoveCompleted(MenuAnimationKind.MoveNext);
    }
    else if (isBackTransition)
    {
        isBackTransition = false;
        if (transittedCount == 1)
        {
            MainPane_MoveCompleted(MenuAnimationKind.MoveFirst);
        }
        else
        {
            MainPane_MoveCompleted(MenuAnimationKind.MovePrevious);
        }
    }
}

internal enum MenuAnimationKind
{
    MoveNext,
    MovePrevious,
    MoveFirst
}

internal event Action<MenuAnimationKind> MainPane_MoveCompleted = null;

そういえば前回の記事のxaml、全部のアニメーションのStoryboardのCompletedを編集してないので大変悲惨です
適当に追加しとくとちゃんと動くと思います

MoveCompletedイベントにenumの引数を追加してどの遷移が終わったかを通知するようにしています
MovePreviousのところはこっちでtransittedCountを変更するほうが安定しそう

ついでにMainPage内のを書き換えるとこんな感じ

private void MainMenuControl_MainPane_MoveCompleted(MenuHostControl.MenuAnimationKind kind)
{
    switch (kind)
    {
        case MenuHostControl.MenuAnimationKind.MoveNext:
            // Stack.Add(_viewModel.PastObject);
            _viewModel.PastObject = _viewModel.MovingObject;
            _viewModel.MovingObject = null;
            break;
        case MenuHostControl.MenuAnimationKind.MoveFirst:
            _viewModel.MainObject = null;
            break;
    } 
}

これで後処理は完了です。1枚目と2枚目の遷移はまともに動く…はず
写真追加してもたぶんわからないのであれ
(というより前回の最終画像の貼り付ける順番変えただけにしかならない)

3枚目→2枚目への遷移

こっちは終わってないので思想だけ

普通にTransittedMain→Transitted→TransittedMainとやってもよさそうですがTransittedMain→別のステート→TransittedMainとやるほうがわかりやすいかなぁなどなど思いつつ

VisualStateManager.GoToStateは普通にやると非同期になるのでifで囲んでアニメーションを2回行います

あとTransitionPaneViewModelに親のTransitionPaneViewModelの参照を持たせるほうがStackなどで管理するよりも楽かなーとも

実装し終わったらまた書きます


一転して短くなってしまった

というわけで3つに分かれてしまったわけですがもうちょっと頑張ります

逆三角に行く日までには終わらせたいなぁ

この辺で