aspnetde / MvvmNano

The small and smart MVVM framework made with ❤ for Xamarin.Forms.
MIT License
59 stars 10 forks source link

How does MvvmNanoTabbedPage work? #13

Closed opcodewriter closed 8 years ago

opcodewriter commented 8 years ago

Any example of using it?

I have an XAML like the following

<?xml version="1.0" encoding="UTF-8"?>
<views:MvvmNanoTabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    xmlns:mvvmNano="clr-namespace:MvvmNano.Forms"
    xmlns:views="clr-namespace:TestXForms.Views"
    xmlns:vm="clr-namespace:TestXForms.ViewModels"
    x:TypeArguments="vm:MainViewModel"
    x:Class="TestXForms.Views.MainPage">
    <ContentPage Title="First Tab">
    </ContentPage>
    <ContentPage Title="Second Tab">
    </ContentPage>
</views:MvvmNanoTabbedPage>
    public partial class MainPage : MvvmNanoTabbedPage<MainViewModel>
    {
        public MainPage ()
        {
            InitializeComponent ();
        }
    }

and I am getting:


[MonoDroid] UNHANDLED EXCEPTION:
[MonoDroid] System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> Ninject.ActivationException: Error activating IPresenter
[MonoDroid] No matching bindings are available, and the type is not self-bindable.
[MonoDroid] Activation path:
[MonoDroid]   1) Request for IPresenter
[MonoDroid] Suggestions:
[MonoDroid]   1) Ensure that you have defined a binding for IPresenter.
[MonoDroid]   2) If the binding was defined in a module, ensure that the module has been loaded into the kernel.
[MonoDroid]   3) Ensure you have not accidentally created more than one kernel.
[MonoDroid]   4) If you are using constructor arguments, ensure that the parameter name matches the constructors parameter name.
[MonoDroid]   5) If you are using automatic module loading, ensure the search path and filters are correct.
[MonoDroid]   at Ninject.KernelBase.Resolve (IRequest request, Boolean handleMissingBindings) [0x00097] in <filename unknown>:0 
[MonoDroid]   at Ninject.KernelBase.Resolve (IRequest request) [0x00000] in <filename unknown>:0 
[MonoDroid]   at Ninject.ResolutionExtensions.GetResolutionIterator (IResolutionRoot root, System.Type service, System.Func`2 constraint, IEnumerable`1 parameters, Boolean isOptional, Boolean isUnique) [0x0002f] in <filename unknown>:0 
[MonoDroid]   at Ninject.ResolutionExtensions.Get[T] (IResolutionRoot root, Ninject.Parameters.IParameter[] parameters) [0x00000] in <filename unknown>:0 
[MonoDroid]   at MvvmNano.MvvmNanoIoC.Resolve[TInterface] () [0x00000] in <filename unknown>:0 
[MonoDroid]   at MvvmNano.MvvmNanoViewModelBase..ctor () [0x00006] in <filename unknown>:0 
[MonoDroid]   at MvvmNano.MvvmNanoViewModel..ctor () [0x00000] in <filename unknown>:0 
[MonoDroid]   at TestXForms.ViewModels.MainViewModel..ctor () [0x00000] in D:\Projects\TestXForms\TestXForms\ViewModels\MainViewModel.cs:8 
[MonoDroid]   at (wrapper managed-to-native) System.Reflection.MonoCMethod:InternalInvoke (System.Reflection.MonoCMethod,object,object[],System.Exception&)
[MonoDroid]   at System.Reflection.MonoCMethod.InternalInvoke (System.Object obj, System.Object[] parameters) [0x00002] in /Users/builder/data/lanes/3540/1cf254db/source/mono/mcs/class/corlib/System.Reflection/MonoMethod.cs:644 
opcodewriter commented 8 years ago

I think I found it:

https://github.com/aspnetde/MvvmNano/blob/master/src/MvvmNano.Forms/MvvmNanoApplication.cs#L56

It's casting MainPage which is a MvvmNanoTabbedPage to .CreateViewFor<TViewModel> () as MvvmNanoContentPage<TViewModel> and the result is null`.

Is MvvmNanoTabbedPage an incomplete implementation? Or maybe I'm just missing something.

Moreover, how is MvvmNanoTabbedPage supposed to work anyway? Since the pages inside the TabbedPage are not created though the usual NavigateTo, their view-models can't be created trough the current flow so to speak. Or maybe presenter needs to be changed to create and set view-models for each page of the TabbedPage? I think this would work.

opcodewriter commented 8 years ago

Issue is I don't see a fast workaround for now... I wasn't expecting to bump into this one

dorange36 commented 8 years ago

If you have a MvvmNanoTabbedPage called LandingPage, here is the XAML for it that contains 4 sub pages.

<?xml version="1.0" encoding="utf-8" ?>
<pages:MvvmNanoTabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:MyAssembly;assembly=MyAssembly"
             xmlns:vm="clr-namespace:MyAssembly.ViewModels"
             xmlns:pages="clr-namespace:MvvmNano.Forms"
             x:Class="MyAssembly.LandingPage"
             x:TypeArguments="vm:LandingViewModel"
             Title="3in1 NextGen">

  <local:HomePage>
    <x:Arguments>
      <vm:HomeViewModel/>
    </x:Arguments>
  </local:HomePage>

  <local:ProgressPage>
    <x:Arguments>
      <vm:ProgressViewModel/>
    </x:Arguments>
  </local:ProgressPage>

  <local:CompletedPage>
    <x:Arguments>
      <vm:CompletedViewModel/>
    </x:Arguments>
  </local:CompletedPage>

  <local:SettingsPage>
    <x:Arguments>
      <vm:SettingsViewModel/>
    </x:Arguments>
  </local:SettingsPage>

</pages:MvvmNanoTabbedPage>

Then for each of your MvvmNanoContentPage pages that you are adding to the TabbedPage you have to add a new constructor so you can manually set the ViewModel.

public partial class HomePage : MvvmNanoContentPage<HomeViewModel>
{
    //add new constructor here
    public HomePage(HomeViewModel model)
    {
        SetViewModel(model);
        InitializeComponent();
    }

    public HomePage()
    {
        InitializeComponent();
    }
}

public partial class ProgressPage : MvvmNanoContentPage<ProgressViewModel>
{
    //add new constructor here
    public ProgressPage(ProgressViewModel model)
    {
        SetViewModel(model);
        InitializeComponent();
    }

    public ProgressPage()
    {
        InitializeComponent();
    }
}

public partial class HomePage : MvvmNanoContentPage<CompletedViewModel>
{
    //add new constructor here
    public CompletedPage(CompletedViewModel model)
    {
        SetViewModel(model);
        InitializeComponent();
    }

    public CompletedPage()
    {
        InitializeComponent();
    }
}

public partial class SettingsPage : MvvmNanoContentPage<SettingsViewModel>
{
    //add new constructor here
    public SettingsPage(SettingsViewModel model)
    {
        SetViewModel(model);
        InitializeComponent();
    }

    public ProgressPage()
    {
        InitializeComponent();
    }
}