2016-03-23 30 views

cevap

6

Hayır. Bu yerleşik değildir, ancak onu geliştirmek kolaydır. Genellikle MvvM çerçeveleri ViewModels tarafından geziniyor. Kaliburn bu modeli takip ediyor. Yani bir çeşit navigasyon servisine ihtiyacı var. Bu gezinme servisi ViewModels için Görünümler oluşturma ve görünüm çerçevesini (bizim durumumuzdaki Xamarin.Froms) belirli gezinme işlevlerini çağırmaktan sorumludur. NavigationPageAdapter, aradığımız şey. Şimdi onu geliştirelim.

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(); 
     } 
    } 
} 

Biz sadece INavigationService uzanır ve bizim ModalNavigationPageAdapter bunu uygulamak arayüzünü IModalNavigationService ilan etti. Ne yazık ki Caliburn, bir çok fonksiyonu özel hale getirdi, bu yüzden bunları kalıtım sürümüne kopyalamamız gerekiyor.

Kalibrede navigationservice.For<VM>().Navigate() üzerinden gezinebilirsiniz. Bu stili takip etmek istiyoruz, bu yüzden bir uzantı yönteminde yaptığımız navigationservice.ModalFor<VM>().Navigate() gibi bir şeyi uygulamak zorundayız.

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

Bu yöntem (Caliburn en NavigateHelper benzer) bizim navigasyon hizmetin kullanımını basitleştiren bir ModalNavigateHelper döndürür. Neredeyse bir kopya, ancak IModalNavigationService için.

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); 
    } 
} 

Son fakat en önemlisi, yeni yerine parlak yeni gezinme servisimizi kullanmak zorundayız. App sınıfı, için NavigationPageAdapter kayıtlarını PrepareViewFirst'da tekil olarak kaydediyor. Biz INavigationService ve IModalNavigationService yönelik navigasyon servisi kaydettirdiğinizin

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); 
    } 
} 

aşağıdaki gibi değiştirmek zorunda.

Açıklamada gördüğünüz gibi, PopModalAsync numaralı telefonu arayarak yakın işlevleri uygulamanız gerekir.