2016-03-23 8 views

答えて

6

いいえ、それはビルドではありませんが、それを強化するのは簡単です。通常、MvvMフレームワークはViewModelでナビゲートしています。キャリバーンはこのパターンに従っています。だから、ある種のナビゲーションサービスが必要です。このナビゲーションサービスは、ViewModelsのビューを作成し、ビューフレームワーク(ここではXamarin.Froms)固有のナビゲーション関数を呼び出します。 NavigationPageAdapterは私たちが探しているものです。さて、それを強化しよう。

public interface IModalNavigationService : INavigationService 
{ 
    Task NavigateModalToViewModelAsync<TViewModel>(object parameter = null, bool animated = true); 
    // TODO: add more functions for closing 
} 

public class ModalNavigationPageAdapter : NavigationPageAdapter, IModalNavigationService 
{ 
    private readonly NavigationPage _navigationPage; 

    public ModalNavigationPageAdapter(NavigationPage navigationPage) : base(navigationPage) 
    { 
     _navigationPage = navigationPage; 
    } 

    public async Task NavigateModalToViewModelAsync<TViewModel>(object parameter = null, bool animated = true) 
    { 
     var view = ViewLocator.LocateForModelType(typeof(TViewModel), null, null); 

     await PushModalAsync(view, parameter, animated); 
    } 

    private Task PushModalAsync(Element view, object parameter, bool animated) 
    { 
     var page = view as Page; 

     if (page == null) 
      throw new NotSupportedException(String.Format("{0} does not inherit from {1}.", view.GetType(), typeof(Page))); 

     var viewModel = ViewModelLocator.LocateForView(view); 

     if (viewModel != null) 
     { 
      TryInjectParameters(viewModel, parameter); 

      ViewModelBinder.Bind(viewModel, view, null); 
     } 

     page.Appearing += (s, e) => ActivateView(page); 
     page.Disappearing += (s, e) => DeactivateView(page); 

     return _navigationPage.Navigation.PushModalAsync(page, animated); 
    } 

    private static void DeactivateView(BindableObject view) 
    { 
     if (view == null) 
      return; 

     var deactivate = view.BindingContext as IDeactivate; 

     if (deactivate != null) 
     { 
      deactivate.Deactivate(false); 
     } 
    } 

    private static void ActivateView(BindableObject view) 
    { 
     if (view == null) 
      return; 

     var activator = view.BindingContext as IActivate; 

     if (activator != null) 
     { 
      activator.Activate(); 
     } 
    } 
} 

私達はちょうどINavigationServiceを拡張し、私たちのModalNavigationPageAdapterでそれを実装するインターフェイスIModalNavigationServiceを宣言しました。残念ながら、Caliburnは多くの機能をプライベートにしていますので、継承バージョンにコピーする必要があります。

キャリバーンでは、navigationservice.For<VM>().Navigate()でナビゲートできます。私たちはこのスタイルに従いたいので、拡張メソッドで行うのはnavigationservice.ModalFor<VM>().Navigate()のようなものを実装する必要があります。

public static class ModalNavigationExtensions 
{ 
    public static ModalNavigateHelper<TViewModel> ModalFor<TViewModel>(this IModalNavigationService navigationService) 
    { 
     return new ModalNavigateHelper<TViewModel>().AttachTo(navigationService); 
    } 
} 

この方法は、(カリバーンのNavigateHelperに似ています)私たちのナビゲーションサービスの利用を簡素化ModalNavigateHelperを返します。それはほぼコピーですが、IModalNavigationServiceです。

public class ModalNavigateHelper<TViewModel> 
{ 
    readonly Dictionary<string, object> parameters = new Dictionary<string, object>(); 
    IModalNavigationService navigationService; 

    public ModalNavigateHelper<TViewModel> WithParam<TValue>(Expression<Func<TViewModel, TValue>> property, TValue value) 
    { 
     if (value is ValueType || !ReferenceEquals(null, value)) 
     { 
      parameters[property.GetMemberInfo().Name] = value; 
     } 

     return this; 
    } 

    public ModalNavigateHelper<TViewModel> AttachTo(IModalNavigationService navigationService) 
    { 
     this.navigationService = navigationService; 

     return this; 
    } 

    public void Navigate(bool animated = true) 
    { 
     if (navigationService == null) 
     { 
      throw new InvalidOperationException("Cannot navigate without attaching an INavigationService. Call AttachTo first."); 
     } 

     navigationService.NavigateModalToViewModelAsync<TViewModel>(parameters, animated); 
    } 
} 

最後に、私たちは古いサービスの代わりに光っている新しいナビゲーションサービスを使用する必要があります。 Appクラスは、にシングルトンとしてINavigationServiceNavigationPageAdapterを登録しています。私たちは、私たちはINavigationServiceIModalNavigationServiceのための私達のナビゲーションサービスを登録している

public class App : FormsApplication 
{ 
    private readonly SimpleContainer container; 

    public App(SimpleContainer container) 
    { 
     this.container = container; 

     container 
      .PerRequest<LoginViewModel>() 
      .PerRequest<FeaturesViewModel>(); 

     Initialize(); 

     DisplayRootView<LoginView>(); 
    } 

    protected override void PrepareViewFirst(NavigationPage navigationPage) 
    { 
     var navigationService = new ModalNavigationPageAdapter(navigationPage); 
     container.Instance<INavigationService>(navigationService); 
     container.Instance<IModalNavigationService>(navigationService); 
    } 
} 

を次のように変更する必要があります。

コメントに見られるように、自分でPopModalAsyncを呼び出すclose関数を実装する必要があります。

関連する問題