MvvmCross: Hybrid Xamarin.Forms and Android Activity Applica



作为MvvmCross的新手,我决定创建一个小型的Xamarin.Forms应用程序。我有一个与它的视图模型MainViewModel.cs绑定的MainPage.xaml,该首先显示。我在机器人项目中有一个FirstView.axml及其活动。关联的 ViewModel 位于 MainViewModel 旁边的核心项目中,并命名为 FirstViewModel.cs

单击导航按钮后,我希望 MvvmCross 显示FirstView.axml布局并绑定到 VM。然而

每当调用该命令时,我都会得到

03-10 10:11:38.704 D/ViewRootImpl(18964): ViewPostImeInputStage ACTION_DOWN
mvx:Diagnostic: 17,87 Showing ViewModel FirstViewModel
03-10 10:11:38.854 I/mono-stdout(18964): mvx:Diagnostic: 17,87 Showing ViewModel FirstViewModel
[0:] mvx:Diagnostic: 17,87 Showing ViewModel FirstViewModel
mvx:Error: 17,91 Failed to create ContentPage FirstPage
03-10 10:11:38.894 I/mono-stdout(18964): mvx:Error: 17,91 Failed to create ContentPage FirstPage
[0:] mvx:Error: 17,91 Failed to create ContentPage FirstPage
mvx:Error: 17,92 Skipping request for FirstViewModel
03-10 10:11:38.904 I/mono-stdout(18964): mvx:Error: 17,92 Skipping request for FirstViewModel
[0:] mvx:Error: 17,92 Skipping request for FirstViewModel`

目前该项目如下所示:

启动活动

[Activity(Label = "Hello MvvmCrossForms", MainLauncher = true)]
public class CrossFormsApp : FormsApplicationActivity
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        //Init forms
        Forms.Init(this, bundle);
        InitialiseMvx();
        //Create mvxformsApp
        var mvxFormsApp = new MvxFormsApp();
        var presenter = Mvx.Resolve<IMvxViewPresenter>() as MvxFormsDroidPagePresenter;
        //Assign the viewPresenter
        presenter.MvxFormsApp = mvxFormsApp;
        LoadApplication(mvxFormsApp);
        //Start mvxApp
        Mvx.Resolve<IMvxAppStart>().Start();
    }
    private void InitialiseMvx()
    {
        if (MvxSingleton<IMvxIoCProvider>.Instance == null)
            Mvx.RegisterSingleton(MvxSimpleIoCContainer.Initialize());
        MvxAndroidSetupSingleton.EnsureSingletonAvailable(this.ApplicationContext)
                                .EnsureInitialized();
    }
}

主视图模型

public class MainViewModel : MvxViewModel
{
    private string _inputString;
    public ICommand NavigateCommand
    {
        get { return new MvxCommand(() => ShowViewModel<FirstViewModel>()); }
    }
    public string InputString
    {
        get { return _inputString; }
        set { SetProperty(ref _inputString, value); }
    }
}

从本质上讲,我正在寻找的是与此相反的: MvvmCross:如何在Android上从常规视图导航到Mvvm视图模型?

在 MvvmCross 中,ViewPresenter 是处理视图之间导航的组件。

所以我们必须创建自己的

  • 继承自MvxFormsDroidPagePresenter,因为我们有一个表单应用程序
  • 重定向非表单调用

    • ChangePresentation(通常用于 Close())
    • Show

    到处理活动的视图演示器 ( MvxAndroidViewPresenter

  • 非表单视图模型列表 ( _androidViews
class HybridDroidViewPresenter : MvxFormsDroidPagePresenter
{
    private readonly MvxAndroidViewPresenter _androidPesenter;
    private readonly List<Type> _androidViews;
    protected Activity Activity => Mvx.Resolve<IMvxAndroidCurrentTopActivity>().Activity;

    public HybridDroidViewPresenter()
    {
        _androidPesenter = new MvxAndroidViewPresenter();
        _androidViews = new List<Type>
        {
            typeof (FirstViewModel)
        };
    }
    public override void ChangePresentation(MvxPresentationHint hint)
    {
        if (Activity.GetType() != typeof (MainActivity))
        {
            // if we are not on the Forms Activity, we assume, we are on an Android Activity
            _androidPesenter.ChangePresentation(hint);
            return;
        }
        base.ChangePresentation(hint);
    }
    public override void Show(MvxViewModelRequest request)
    {
        if (_androidViews.Contains(request.ViewModelType))
        {
            _androidPesenter.Show(request);
            return;
        }
        base.Show(request);
    }
}

要注册我们的新视图演示器,我们必须在设置中覆盖CreateViewPresenter

public class Setup : MvxAndroidSetup
{
    // ...
    protected override IMvxAndroidViewPresenter CreateViewPresenter()
    {
        var presenter = new HybridDroidViewPresenter();
        Mvx.RegisterSingleton<IMvxViewPresenter>(presenter);
        return presenter;
    }
}

我们的视图演示器和MvxAndroidViewPresenter需要IMvxAndroidCurrentTopActivity。所以我们需要让它知道我们MainActivity的生命周期。这可以通过IMvxAndroidActivityLifetimeListener和修改活动来完成,如下所示:

[Activity(Label = "MainActivity", ScreenOrientation = ScreenOrientation.Portrait)]
public class MainActivity
    : FormsApplicationActivity
{
    private IMvxAndroidActivityLifetimeListener _lifetimeListener;
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        Forms.Init(this, bundle);
        var mvxFormsApp = new MvxFormsApp();
        LoadApplication(mvxFormsApp);
        var presenter = (MvxFormsDroidPagePresenter) Mvx.Resolve<IMvxViewPresenter>();
        presenter.MvxFormsApp = mvxFormsApp;
        Mvx.Resolve<IMvxAppStart>().Start();
        _lifetimeListener = Mvx.Resolve<IMvxAndroidActivityLifetimeListener>();
        _lifetimeListener.OnCreate(this);
    }
    protected override void OnDestroy()
    {
        _lifetimeListener.OnDestroy(this);
        base.OnDestroy();
    }
    protected override void OnNewIntent(Intent intent)
    {
        base.OnNewIntent(intent);
        _lifetimeListener.OnViewNewIntent(this);
    }
    protected override void OnResume()
    {
        base.OnResume();
        _lifetimeListener.OnResume(this);
    }
    protected override void OnPause()
    {
        _lifetimeListener.OnPause(this);
        base.OnPause();
    }
    protected override void OnStart()
    {
        base.OnStart();
        _lifetimeListener.OnStart(this);
    }
    protected override void OnRestart()
    {
        base.OnRestart();
        _lifetimeListener.OnRestart(this);
    }
    protected override void OnStop()
    {
        _lifetimeListener.OnStop(this);
        base.OnStop();
    }
}

现在我们能够通过以下方式导航到我们的FirstViewModel

ShowViewModel<FirstViewModel>()

并且FirstActivity看起来像一个普通的MvvMCross Android Activity,并将FirstView.axml设置为ContentView

[Activity(Label = "FirstActivity")]
public class FirstActivity : MvxActivity<FirstViewModel>
{
    protected override void OnCreate(Bundle savedInstanceState)
    {
        base.OnCreate(savedInstanceState);
        SetContentView(Resource.Layout.FirstView);
    }
}

请注意:

  • 这样,您无法导航到非表单视图表单(但非表单视图),除非通过Close()或后退按钮
  • 返回
  • 生命周期可能会留下一些问题(例如逻辑删除)
  • MvvMCross 的开发人员对 MvvMCross 的表单支持不满意,因此表单演示器可能会有一些重大更改

我最终做的是定义一个空接口IXFViewModel,我在Forms ViewModels上实现该接口。然后,在我的自定义演示器中,我得到了MvxViewModelRequest.ViewModelType实现的接口列表。

如果在接口列表中找到类型 IXFViewModel,则自定义演示者(扩展MvxFormsDroidPagePresenter)通过调用 base.Show(request) 来处理演示文稿。如果未找到IXFViewModel类型,则自定义演示者将切换到MvxAndroidViewPresenter来处理视图演示。

解决方案如下:

启动

public class Setup : MvxAndroidSetup
{
    /// prefix ///
    protected override IMvxAndroidViewPresenter CreateViewPresenter()
    {
        var presenter = new XFDroidPresenter();
        Mvx.RegisterSingleton<IMvxViewPresenter>(presenter);
        return presenter;
    }
}

自定义演示者

public class XFDroidPresenter : MvxFormsDroidPagePresenter
{
    protected MvxAndroidViewPresenter DroidPresenter { get; set; }
    protected Activity Activity { get { return Mvx.Resolve<IMvxAndroidCurrentTopActivity>().Activity; } }
    public XFDroidPresenter()
    {
        DroidPresenter = new MvxAndroidViewPresenter();
    }
    public override void ChangePresentation(MvxPresentationHint hint)
    {
        if(Activity.GetType() != typeof(CrossFormsApp))
        {
            DroidPresenter.ChangePresentation(hint);
            return;
        }
        base.ChangePresentation(hint);
    }
    public override void Show(MvxViewModelRequest request)
    {
        var implementedInterfaces = request.ViewModelType
                                           .GetInterfaces()
                                           .ToList();
        if (!implementedInterfaces.Contains(typeof(IXFViewModel)))
        {
            DroidPresenter.Show(request);
            return;
        }
        base.Show(request);
    }
}

启动器和窗体活动

[Activity(Label = "Hello MvvmCrossForms", Icon = "@drawable/icon", MainLauncher = true)]
public class CrossFormsApp : FormsApplicationActivity
{
    private MvxAndroidLifetimeMonitor _lifeTimeMonitor;
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        Forms.Init(this, bundle);
        InitialiseMvx();
        var mvxFormsApp = new MvxFormsApp();
        var presenter = Mvx.Resolve<IMvxViewPresenter>() as MvxFormsDroidPagePresenter;
        presenter.MvxFormsApp = mvxFormsApp;
        LoadApplication(mvxFormsApp);
        Mvx.Resolve<IMvxAppStart>().Start();
        _lifeTimeMonitor = Mvx.Resolve<IMvxAndroidCurrentTopActivity>() as MvxAndroidLifetimeMonitor;
        _lifeTimeMonitor.OnCreate(this);
    }
    private void InitialiseMvx()
    {
        if (MvxSingleton<IMvxIoCProvider>.Instance == null)
            Mvx.RegisterSingleton(MvxSimpleIoCContainer.Initialize());
        MvxAndroidSetupSingleton.EnsureSingletonAvailable(this.ApplicationContext)
                                .EnsureInitialized();
    }
    protected override void OnStart()
    {
        base.OnStart ();
        _lifeTimeMonitor.OnStart(this);
    }
    protected override void OnRestart()
    {
        base.OnRestart ();
        _lifeTimeMonitor.OnRestart(this);
    }
    protected override void OnResume()
    {
        base.OnResume ();
        _lifeTimeMonitor.OnResume(this);
    }
    protected override void OnDestroy()
    {
        base.OnDestroy ();
        _lifeTimeMonitor.OnDestroy(this);
    }
}

界面和视图模型

public interface IXFViewModel
{
}
public class MainViewModel : MvxViewModel, IXFViewModel
{
    private string _inputString;
    public ICommand NavigateCommand
    {
        get { return new MvxCommand(() => Close(this)); }
    }
    public string InputString
    {
        get { return _inputString; }
        set { SetProperty(ref _inputString, value); }
    }
}

相关内容

  • 没有找到相关文章

最新更新