Hi there,
I'm fighting with a problem in combination with Xamarin.Forms, Prism.Forms and AutoFac.
I have a ContentPage with a Syncfusion.NavigationDrawer on it. The menu items are switching ContentViews for the different menu items.
XAML stuff:
<navigationdrawer:SfNavigationDrawer.ContentView>
<Grid BackgroundColor="White">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackLayout BackgroundColor="#1aa1d6" Orientation="Horizontal">
<Button Image="threelines.png" HeightRequest="50" WidthRequest="50" HorizontalOptions="Start" BackgroundColor="#1aa1d6" Clicked="HamburgerClicked"/>
</StackLayout>
<ContentView Grid.Row="1" Content="{Binding ViewContent}"/>
</Grid>
</navigationdrawer:SfNavigationDrawer.ContentView>
C# stuff:
public MainPageViewModel(INavigationService navigationService, IDataService dataService)
: base(navigationService)
{
this.dataService = dataService;
this.NavigationItemTapped = new DelegateCommand<NavigationItem>(this.NavItemTapped);
this.NavigationItems = new ObservableCollection<NavigationItem>
{
new NavigationItem() { Text = AppResource.Dashboard, ViewType = typeof(DashboardView) },
new NavigationItem() { Text = AppResource.Canteens, ViewType = typeof(CanteenBrowserView) },
new NavigationItem() { Text = AppResource.Profile, ViewType = typeof(ProfileView) }
};
}
private void ActivateView(NavigationItem item)
{
this.ViewContent = (ContentView)Activator.CreateInstance(item.ViewType);
this.Title = item.Text;
}
private void NavItemTapped(NavigationItem item)
{
ActivateView(item);
}
I'm autowiring separate ViewModels to the ContentViews using prism:ViewModelLocator.AutowireViewModel="True"
.
To get that working I registered the ViewModels using the ContainerBuilder. Each ViewModel derives from a base class holding a property for
IComponentContext. I use that property to resolve services in the ViewModels (e.g. a DataService)
protected override void RegisterTypes(IContainerRegistry containerRegistry)
{
var builder = containerRegistry.GetBuilder();
if (this.Mocking)
{
builder.RegisterType<MockDataService>().As<IDataService>().SingleInstance();
}
else
{
builder.RegisterType<DataService>().As<IDataService>().SingleInstance();
}
builder.RegisterType<Configuration>().As<IConfiguration>().SingleInstance();
builder.Register(c => new DashboardViewModel() { ComponentContext = c.Resolve<IComponentContext>() });
builder.Register(c => new CanteenBrowserViewModel() { ComponentContext = c.Resolve<IComponentContext>() });
containerRegistry.RegisterForNavigation<NavigationPage>();
containerRegistry.RegisterForNavigation<MainPage>();
containerRegistry.RegisterForNavigation<SignUpPage>();
containerRegistry.RegisterForNavigation<SignInPage>();
}
Basically the stuff is working the first time showing a ContentView. For example when showing the DashBoardView-Content the first time, I can resolve the IDataService using:
var dataService = this.ComponentContext.Resolve<IDataService>();
When I switch to the other view CanteenBrowserView and then back again, resolving IDataService leads into:
System.ArgumentNullException
HResult=0x80004003
Message=Value cannot be null.
Parameter name: context
Source=Autofac
StackTrace:
at Autofac.ResolutionExtensions.ResolveService(IComponentContext context, Service service, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context, IEnumerable`1 parameters)
at Autofac.ResolutionExtensions.Resolve[TService](IComponentContext context)
at mealticker.ViewModels.DashboardViewModel.<Initializer>d__13.MoveNext() in D:\DEV\mealticker-mobile\mealticker\mealticker\ViewModels\DashboardViewModel.cs:line 29
I have no idea why that happens. Can anyone find the bug?
Or is there another best practise out there to implement such things?
Any help is appreciated.
Regards,
Maxx