TabbedPage with multiple Tabs with different View Models BindingContext

AvoirAvoir Member ✭✭

Hi
I am new to mobile app development so hopefully the following will make sense.

I have a page Projects with a ListView with the following code: -->
async void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
{
var project = args.SelectedItem as Project;
if (project == null)
return;
var projectTab = new ProjectTabsPage();
projectTab.BindingContext = new ProjectTabsViewModel(project);
await Navigation.PushAsync(projectTab) ;

        // Manually deselect item.
        ProjectsListView.SelectedItem = null;
    }

My ProjectTabsViewModel looks like this:-->
public class ProjectTabsViewModel : BaseViewModel
{
public ProjectDetailViewModel projectDetailViewModel { get; set; }
public ProblemDetailViewModel problemDetailViewModel { get; set; }

    public ProjectTabsViewModel(Project project)
    {
        projectDetailViewModel = new ProjectDetailViewModel(project);
        problemDetailViewModel = new ProblemDetailViewModel(project.id);
    }
}

My ProjectTabsPage looks like this: -->

<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
         xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
         xmlns:d="http://xamarin.com/schemas/2014/forms/design"
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
         xmlns:local="clr-namespace:ToolA.Views;assembly=ToolA"
         Title="{Binding Title}"
         x:Class="ToolA.Views.ProjectTabsPage">
    <!--Pages can be added as references or inline-->
    <local:ProjectDetailPage Title="Project Details" BindingContext="{Binding projectDetailViewModel}"></local:ProjectDetailPage>
    <local:ProblemsPage Title="Problems" BindingContext="{Binding problemDetailViewModel}"></local:ProblemsPage>
</TabbedPage>

And its c#: -->
public partial class ProjectTabsPage : TabbedPage
{
public ProjectTabsPage()
{
InitializeComponent();
}
}

So when I go from Projects list page to the project details page (Tab 1), the page knows about its projectDetailViewModel. However, when I click on the Problems tab (tab 2), problemDetailViewModel is null even if it was set in ProjectTabsViewModel .

Any ideas what I am doing wrong? Or if I am approaching this the wrong way?

All I want to do is display the parent record details (project) under tab 1 and a list of child records (problems) under tab 2.

Thanks.

Tagged:

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai

    Try to share the code of your problemDetailViewModel and ProblemsPage.
    Where do you find the problemDetailViewModel is null.

    public ProblemsPage()
    {
        InitializeComponent();
    
        // It is null here
        var viewModel = BindingContext;
    }
    
    protected override void OnAppearing()
    {
        base.OnAppearing();
    
        var viewModel = BindingContext;
    }
    

    You will get the correct binding context in your page's OnAppearing lifecycle.

  • AvoirAvoir Member ✭✭

    Thank you for your reply.

    I have now changed my ProblemsPage so it looks like this:

    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class ProblemsPage : ContentPage
    {
    ProblemDetailViewModel problemDetailViewModel;

        public ProblemsPage(ProblemDetailViewModel viewModel)
        {
            InitializeComponent();
            BindingContext = this.problemDetailViewModel = viewModel;
        }
    
        public ProblemsPage()
        {
            InitializeComponent();
            var viewModel = BindingContext;
        }
    
        async void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
        {
            var problem = args.SelectedItem as Problem;
            if (problem == null)
                return;
            ProblemsListView.SelectedItem = null;
        }
    
        async void AddRecord_Clicked(object sender, EventArgs e)
        {
            await Navigation.PushAsync(new ProjectNewPage());
        }
    
        protected override void OnAppearing()
        {
            base.OnAppearing();
            problemDetailViewModel = BindingContext as ProblemDetailViewModel;
            problemDetailViewModel.GetProblemsForProject();
            ObservableCollection<Problem> problems = new ObservableCollection<Problem>(problemDetailViewModel.Problems);
            ProblemsListView.ItemsSource = problems;
        }
    }
    

    And my ProblemDetailViewModel is now like this:

    public class ProblemDetailViewModel : BaseViewModel
    {
        public Problem Problem { get; set; }
        public int project_id { get; set; }
        public IEnumerable<Problem> Problems { get; set; }
    
        public ProblemDetailViewModel(Problem problem = null)
        {
            Title = problem?.title;
            Problem = problem;
        }
    
        public ProblemDetailViewModel(int project_id)
        {
            this.project_id = project_id;
        }
    
        public void GetProblemsForProject()
        {
            ProblemDataAccess dataAccess = new ProblemDataAccess();
            Problems = dataAccess.GetFilteredProblems(project_id);
        }
    }
    

    I am now getting the project_id from the BindingContext on my ProblemsPage's OnAppearing so the following now works it seems:

    base.OnAppearing();
            problemDetailViewModel = BindingContext as ProblemDetailViewModel;
            problemDetailViewModel.GetProblemsForProject();
    
  • LandLuLandLu Member, Xamarin Team Xamurai

    Do you mean your issue has been solved?

Sign In or Register to comment.