2

caliburn.micro INavigationService (FrameAdapter) を使用して正常に動作している WinRT アプリがあります。問題は、アプリ内のすべてのページがフル ページであり、多くのビュー xaml マークアップを繰り返すことです。私がやりたいことは、メイン レイアウトを定義し、ContentControl を含み、Conductor パターンを使用して ContentControl のコンテンツを切り替えるシェル ビューを持っている "MasterPages" タイプのアーキテクチャをさらに持つことです。過去にこの種のアーキテクチャで WPF と Silverlight を使用して成功したことがあるので、WinRT でも可能だと思います。

問題は、ナビゲーション インフラストラクチャ (FrameAdapter を使用) と、コンダクタの ActiveItem にバインドされた ContentControl を使用するコンダクタ インフラストラクチャ (SimpleNavigation サンプルなど) の間に切断があるように見えることです。

コンダクターのシナリオでは、ActivateItem を使用します。

ActivateItem(new MyViewModel());

しかし、INavigationService では NavigateToViewModel を使用します。

navigationService.NavigteToViewModel<MyViewModel>();

私が知る限り、この 2 つは関連していないようです。

私が持っていた 1 つのアイデアは、INavigationService を実装し、基本的に子画面の作成とアクティブ化を処理する ConductorNavigationService を作成することでした。可能だと思われますが、それほど単純ではないように思われるので、caliburn.micro でこれを行う方法が既にサポートされているかどうかを確認することにしました。

4

1 に答える 1

3

WinRT や を使用したことがないので、私の理解は少し緊張しているかもしれませんが、RT の一部であり、ビューモデルの解像度とフレームのナビゲーションを提供してINavigationServiceいると思います。FrameINavigationService

私のもう 1 つの仮定は、あなたのフレームはすでにコンダクターに少し似ているということです。フレームで 'Navigate()' を呼び出すと、フレームのコンテンツが新しく指定されたコンテンツに置き換えられるだけです。この場合、CM はビューモデルのビューの最初の解決を行っています。

コンダクターのルートに行きたいので、CM の実装を捨ててINavigationService、独自のナビゲーション メソッドを処理するようにします (たとえば、 sメソッドをINavigationServiceスキップします)。FrameNavigate()

CM ソースをざっと見てみると、すべてがフレームでイベントをNavigationService処理しNavigate、次に VM の解決とビューの設定を行っていることがわかります (コンダクターはおそらく既に行っていることです)。あなたがする必要があるINavigationServiceのは、フレームをナビゲートする代わりに、実装が指定されたビューをシェルにロードするだけであることを確認することです

のコンストラクター コードを盗んでNavigationServiceの実装を変更し、x が VM のインスタンスであるシェルをNavigate()呼び出すだけで済みます。ActivateItem(x)CM が残りの処理を行います (CM ブーストラップはルートの「フレーム」も既にセットアップしていると思いますので、心配する必要はありません)。

例えば

実装は次のようになります (これは私がまとめたものであり、むき出しの嘘である可能性があることに注意してください!):

public class NewFrameAdapter : INavigationService
{
    private readonly Frame frame;
    private readonly IConductActiveItem shell;
    private event NavigatingCancelEventHandler ExternalNavigatingHandler = delegate { };

    public NewFrameAdapter(Frame frame)
    {
        this.frame = frame;

        // Might want to tighten this up as it makes assumptions :)
        this.shell = (frame as FrameworkElement).DataContext as IConductActiveItem;
    }

    public bool Navigate(Type pageType)
    {
        // Do guardclose and deactivate stuff here by looking at shell.ActiveItem
        // e.g.
        var guard = shell.ActiveItem as IGuardClose;

        if (guard != null)
        {
            var shouldCancel = false;
            guard.CanClose(result => { shouldCancel = !result; });

            if (shouldCancel)
            {
                e.Cancel = true;
                return;
            }
        }

        // etc

        // Obviously since the guard is probably async (assume it is, if not you are ok to continue!) you'd have to not call this code right 
        // here but I've just stuck it in here as an example

        // edit: looking at the code above (the guard code) it looks like this is all sync so the below code should be fine

        // You might get away with calling shell.ActivateItem(pageType) as I'm not sure
        // if the viewmodel binder in RT would resolve this all for you, but if it doesnt...

        // Init the view and then resolve the VM type
        ViewLocator.InitializeComponent(pageType);

        var viewModel = ViewModelLocator.LocateForView(pageType);

        // Activate the VM in the shell)
        shell.ActivateItem(viewModel);
    }

これを独自の方法で転がすのはそれほど難しくありません。これはまったく役に立ちますか?

次に、XAML は非常に単純になります。

<Frame blah blah>
  <SomeStaticContent />
  <ContentControl x:Name="ActiveItem" /> <!-- The dynamic bit... -->
  <SomeMoreStaticContent />
</Frame>

これはおそらくビュー ファーストとビューモデル ファーストのハイブリッドになると考えています。これは、ルートFrameがビュー ファーストを使用し、コンダクターが使用しActivateItem()てビューモデルを取得し、バインダーが起動したときにビューを解決するためです。しかし、私の仮定が正しければ、うまくいくはずです

于 2012-12-05T17:07:16.123 に答える