Using Navigation in MasterDetailPage with Autofac

2019-07-11 02:22发布

I'm trying to use Autofac in Xamarin.Forms project. I created basic samples successfully, even used ViewFactory for some more complicated samples.

However, I'm unable to use MasterDetailPage along with Navigation.

I'm using factories and services written by Jonathan Yates. You can find his code here

My Application Bootstrapper:

protected override void ConfigureApplication(IContainer container)
{
    var viewFactory = container.Resolve<IViewFactory>();
    var mainPage = viewFactory.Resolve<TestViewModel1>();

    var navigationPage = new NavigationPage(mainPage);
    var masterPage = new ContentPage();
    masterPage.Title = "asd";
    _application.MainPage = new MasterDetailPage()
    {
        Master = masterPage,
        Detail = navigationPage

    };
}

My TestViewModel1 has a command that navigates to TestViewModel2:

ButtonCommand = new Command(async()=>await _navigator.PushAsync<TestViewModel2>());

However, the app crashes with Exception saying

Cannot cast from source type to destination type.

This happens when the Navigator is pushing the next page.

StackTrace:

" at TestIoc.TestModule+<>c.b__0_0 () [0x00000] in C:\Users\dushyantb\Documents\Visual Studio 2015\Projects\TestIoc\TestIoc\TestIoc\TestModule.cs:27 \n at TestIoc.Views.PageProxy.get_Navigation () [0x00001] in C:\Users\dushyantb\Documents\Visual Studio 2015\Projects\TestIoc\TestIoc\TestIoc\Views\PageProxy.cs:39 \n at TestIoc.Navigator.get_Navigation () [0x00001] in C:\Users\dushyantb\Documents\Visual Studio 2015\Projects\TestIoc\TestIoc\TestIoc\Services\Navigator.cs:26 \n at TestIoc.Navigator+d__8`1[TestIoc.ViewModels.TestViewModel2].MoveNext () [0x0003a] in C:\Users\dushyantb\Documents\Visual Studio 2015\Projects\TestIoc\TestIoc\TestIoc\Services\Navigator.cs:58 "

what am I doing wrong?

Note: The navigation works when there's no MasterDetailPage.

1条回答
别忘想泡老子
2楼-- · 2019-07-11 03:05

Be sure not to override the PageResolver, eg. don't take the override Jonathan uses in his WeatherApp sample:

builder.RegisterInstance<Func<Page>>(() => ((NavigationPage)Application.Current.MainPage).CurrentPage);

The default implementation of the PageResolver Func in the core component takes care of MasterDetail scenarios. See AutoFacModule.cs:

            // default page resolver
            builder.RegisterInstance<Func<Page>>(() =>
            {
                // Check if we are using MasterDetailPage
                var masterDetailPage = Application.Current.MainPage as MasterDetailPage;

                var page = masterDetailPage != null 
                    ? masterDetailPage.Detail 
                    : Application.Current.MainPage;

                // Check if page is a NavigationPage
                var navigationPage = page as IPageContainer<Page>;

                return navigationPage != null 
                    ? navigationPage.CurrentPage
                        : page;
            }
        );

I have tested MasterDetail scenario with NavigationPage DetailViews succesfully with Jonathan's framework. So it should work.

In my case, the bootstrapping code is

        protected override void ConfigureApplication(IContainer container)
        {

            // set main page
            var viewFactory = container.Resolve<IViewFactory>();

            var mainPage = viewFactory.Resolve<MainPageViewModel> ();
            _application.MainPage = mainPage;

        }

That means, i have a MainPageView, which is a MasterDetailPage and which takes care of setting up it's child views:

    public class MainPage : MasterDetailPage
    {
        public MainPage (IViewFactory viewfactory)
        {
            Master = viewfactory.Resolve<MenuPageViewModel>();

            Detail = new NavigationPage (viewfactory.Resolve<DetailViewModel1>());

        }
    }

The MenuPageViewModel also uses IViewFactory to switch the MasterPages' Detail:

public class MenuPageViewModel : ViewModelBase
{
    IViewFactory _viewFactory;
    public MenuPageViewModel (IViewFactory viewFactory)
    {
        _viewFactory = viewFactory;

        ShowDetail1Command = new Command (ShowDetail1);
        ShowDetail2Command = new Command (ShowDetail2);
    }


    public ICommand ShowDetail1Command { get; set;}
    public void ShowDetail1() {
        var mainPage = _viewFactory.Resolve<MainPageViewModel> ();

        ((MasterDetailPage)mainPage).Detail = new NavigationPage (_viewFactory.Resolve<DetailViewModel1> ());
    }

    public ICommand ShowDetail2Command { get; set;}
    public void ShowDetail2() {
        var mainPage = _viewFactory.Resolve<MainPageViewModel> ();

        ((MasterDetailPage)mainPage).Detail = new NavigationPage (_viewFactory.Resolve<DetailViewModel2> ());
    }

}

Hope this helps.

查看更多
登录 后发表回答