Forum Xamarin.Forms

Xamarin MVVM Reference Content View and Pass Parameters Too

Hello there! Working in xamarin forms. How do I reference a content view from a content page but also include passing information like below?

await Navigation.PushAsync(new SecondContentPage(new NextViewModel(FirstViewModel.id)));

I've tried xaml binding context but don't know where to go from there and it keeps giving me errors about a parameterless constructor.

xmlns:viewmodel="clr-namespace:Project.ViewModels"

   <StackLayout>
        <local:SecondContentView>
            <local:SecondContentView.BindingContext>
                <viewmodel:NextViewModel></viewmodel:NextViewModel>
            </local:SecondContentView.BindingContext>
        </local:SecondContentView>
    </StackLayout>

I need the id passed along basically so that the list can run on the content view. thanks all

Best Answer

Answers

  • NMackayNMackay GBInsider, University mod

    This scenario is supported in Prism.

  • LandLuLandLu Member, Xamarin Team Xamurai

    Firstly, add a constructor with a parameter like:

    public class CustomView : ContentView
    {
        NextViewModel model;
        public CustomView(NextViewModel parameter)
        {
            model = parameter;
        }
        public CustomView()
        {
    
        }
    }
    

    Then we could pass parameters in the Xaml like:

    <StackLayout>
        <local:CustomView>
            <x:Arguments>
                <viewmodel:NextViewModel/>
            </x:Arguments>
        </local:CustomView>
    </StackLayout>
    

    But I suggest using bindable property as it is much more flexible:

    public class CustomView : ContentView
    {
        public static readonly BindableProperty ModelProperty = BindableProperty.Create(nameof(Model), typeof(NextViewModel), typeof(CustomView), propertyChanged: SettingsValueChanged);
    
        public NextViewModel Model
        {
            set => SetValue(ModelProperty, value);
            get => (NextViewModel)GetValue(ModelProperty);
        }
    
        public static void SettingsValueChanged(BindableObject bindableObject, object oldValue, object newValue)
        {
            // get the model using new value here
        }
        public CustomView()
        {
    
        }
    }
    

    Consume it like:

    <ContentPage.Resources>
        <viewmodel:NextViewModel x:Key="NextViewModel"/>
    </ContentPage.Resources>
    <StackLayout>
        <local:CustomView Model="{StaticResource NextViewModel}"/>
    </StackLayout>
    
  • AaronBlaylockAaronBlaylock USMember ✭✭

    give it a try right now thank you

  • LandLuLandLu Member, Xamarin Team Xamurai

    Feel free to ask here if you have any concerns.

  • AaronBlaylockAaronBlaylock USMember ✭✭
    edited February 26

    Updated - I created some new example code. I created one page to nest a second page with a Listview. Works great until I try to pass a parameter with x:Arguments or in a ViewModel constructor.

    First page

    **<StackLayout>
    
            <StackLayout>
                <Label Text="First Page Content"></Label>
            </StackLayout>
    
            <StackLayout>
                <local:SecondContentView>
                    <local:SecondContentView.BindingContext>
                        <viewmodel:SecondViewModel>
                            <x:Arguments>102</x:Arguments>
                        </viewmodel:SecondViewModel>
                    </local:SecondContentView.BindingContext>
                </local:SecondContentView>
            </StackLayout>
    
        </StackLayout>**
    

    second page

            <ContentView.Content>
    
        <StackLayout>
    
            <Label Text="Second Page"></Label>
    
            <ListView x:Name="FirstListView">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <ViewCell>
                            <StackLayout Padding="10">
                                <Label Text="{Binding pType}"></Label>
                                <Label Text="{Binding fDepartment}"></Label>
                                <Label Text="{Binding Description}"></Label>
                            </StackLayout>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
    
            </ListView>
    
        </StackLayout>
    
    </ContentView.Content>
    

    second page's code behind

    SecondViewModel ViewModel;
    
        public SecondContentView(SecondViewModel viewmodel)
        {
            InitializeComponent();
    
            BindingContext = ViewModel = viewmodel;
    
            FirstListView.ItemsSource = ViewModel.TypeList;
        }
    

    second page's view model

    **public List<TypeModel> TypeList;
    
        public SecondViewModel(int parameter)
        {
            var p = parameter;
    
            TypeList = new List<TypeModel>()
            {
                new TypeModel { pType = 1, Title = "First Type", Description = "First Description", Version = "9.9.9", fDepartment = 101 , Comments = "None"},
                new TypeModel { pType = 2, Title = "Second Type", Description = "Second Description", Version = "9.9.9", fDepartment = 101 , Comments = "None"},
                new TypeModel { pType = 3, Title = "Third Type", Description = "Third Description", Version = "9.9.9", fDepartment = 102 , Comments = "None"},
                new TypeModel { pType = 4, Title = "Fourth Type", Description = "Fourth Description", Version = "9.9.9", fDepartment = 102 , Comments = "None"}
            };
    
        }**
    
  • AaronBlaylockAaronBlaylock USMember ✭✭
    edited February 27

    I keep getting the same error (and throughout this whole situation) as before about the view models constructor.

    Type 'SecondViewModel' is not usable as an object element because it is not public or does not define a public parameterless constructor or a type converter

        <StackLayout>
                        <local:SecondContentView>
                            <local:SecondContentView.BindingContext>
                                <local:SecondViewModel>
                                    <x:Arguments>
                                        <x:Double>102</x:Double>
                                    </x:Arguments>
                                </local:SecondViewModel>
                            </local:SecondContentView.BindingContext>
                        </local:SecondContentView>
                    </StackLayout>
    
  • LandLuLandLu Member, Xamarin Team Xamurai

    Did you get it from my sample?
    It worked properly on my side:

    To make the instantiating work in xmal we also need to define a corresponding constructor for SecondViewModel like:

    public SecondViewModel(double parameter)
    {
        // ...
    }
    

    Change the type to double here.

  • AaronBlaylockAaronBlaylock USMember ✭✭

    My bad was trying to not copy and paste and do it on my own. Was a typo in my xaml. LandLu you rock. Thank you and you are an ambassador to xamarin.

    One more question how did you do that little mini video?

Sign In or Register to comment.