Caliburn.Micro 3.0(和Caliburn.Micro.Xamarin.Forms)是否实现了在Xamarin.Forms中模仿/支持Navigation.PushModalAsync
的功能?
答案 0 :(得分:9)
没有。它不是内置的,但它很容易增强它。通常,MvvM框架由ViewModels导航。 Caliburn遵循这种模式。所以它需要某种导航服务。该导航服务负责为ViewModel创建视图,并调用视图框架(在我们的例子中为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();
}
}
}
我们刚刚声明了扩展IModalNavigationService
的接口INavigationService
并在ModalNavigationPageAdapter
中实现了它。不幸的是,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);
}
}
此方法返回ModalNavigateHelper
,简化了导航服务的使用(类似于Caliburn的NavigateHelper
)。它几乎是一个副本,但对于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
班级正在NavigationPageAdapter
中将INavigationService
PrepareViewFirst
注册为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);
}
}
中的单身人士。我们必须按如下方式进行更改
INavigationService
我们正在为IModalNavigationService
和PopModalAsync
注册我们的导航服务。
正如您在评论中看到的那样,您必须实现自己调用public static Hashmap<String, Clans> playersClan = new Hashmap<>();
的关闭函数。