0
votes

I have been trying to transfer/populate data between tabbed pages. The general idea of what I am trying to do is to insert a product info in "Insert/Edit" page which then can be viewed in the "Overview" page. The saved products are populated in a listview.

I am very new to MVVM and Xamarin. The scenario I am having trouble with is when user click an item from the listview in "Overview" page, it should then populate the stored information in "Insert/Edit" page so that the user can edit the product info. I was able to display most of the product info except for picker. It just showed empty.

enter image description here

Is my TabbedViewModel wrong? Can someone point me to a right direction? Below is my tabbedpage xaml code.

<TabbedPage 
... 
...>
    <Views:InsertEdit Title="Insert/Edit" Icon="edit.png" BindingContext="{Binding productViewModel}"></Views:InsertEdit>
    <Views:Overview Title="Overview" Icon="list.png"></Views:Overview>
</TabbedPage>

I use a TabbedViewModel to bind product info between "Insert/Edit" page & "Overview" page

namespace Prototype
{
    public class TabbedViewModel
    {
        public Product productViewModel { set; get; }

        public TabbedViewModel(Product product)
        {
            productViewModel = product;
        }
    }
}

The product info is as per Product model

public class Product
{
        [PrimaryKey, AutoIncrement]
        public int id { get; set; }
        public string productCode { get; set; }
        public string description { get; set; }
        public string merchant { get; set; }
        public string remarks { get; set; }
        public string conditionCode { get; set; }
        public string conditionName { get; set; }
        
}

The product condition is as per ProductCondition model

public class ProductCondition
{
        
        public string conditionCode { get; set; }
        public string conditionName { get; set; }
        
}

In the picker list, only conditionName is displayed. But when saving product info into the Product table, conditionName and conditionCode is stored together.

Below is my InsertEdit content page code

public partial class InsertEdit : ContentPage
{
    Product product;

    public InsertEdit()
    {
        InitializeComponent();
        InitializeData();
    }
    
    private async void InitializeData()
    {
        List<ProductCondition> conditionList = await App.DbHelper.GetConditionListAsync();
        picker.ItemsSource = conditionList;
    }

    // Upon clicking enter key in the entry text field, search for product info based on the product code user has keyed in
    async void EditorProductCode_Completed(object sender, EventArgs e)
    {
        var text = ((Entry)sender).Text; //cast sender to access the properties of the Entry

        if (string.IsNullOrEmpty(text))
        {
            await DisplayAlert("Warning", "Invalid", "OK");
        }
        else
        {

            product = await App.DbHelper.GetProduct(text);
            populateData();
        }
    }

    async void populateData() {
        if (product == null)
        {
            product = new Product();
            product = null;
            await DisplayAlert("Warning", "Invalid product code.", "OK");
        }

        picker.SelectedItem = ((List<ProductCondition>)picker.ItemsSource).FirstOrDefault(c => c.conditionCode == product.conditionCode);

        BindingContext = product;
    }

   
   // Upon clicking the save button
    async void OnSaveButtonClicked(object sender, EventArgs e)
    {
        product.conditionCode = ((ProductCondition)picker.SelectedItem).conditionCode;
        product.conditionName = ((ProductCondition)picker.SelectedItem).conditionName;
        await App.DbHelper.SaveProductAsync(product);

        DependencyService.Get<IMessage>().LongAlert("Product has been saved!");

    }

}

Below is the picker xaml code

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="2.1*" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition Width="5*" />
    </Grid.ColumnDefinitions>
    <Label Text="Product Condition" 
       HorizontalOptions="Start"
       VerticalOptions="Center"/>
    <Label Grid.Column="1"
       HorizontalOptions="Start"
       VerticalOptions="Center"
       Text=":"/>
    <Picker Grid.Column="2"
        Title="Select Condition" 
        x:Name="picker" 
        FontSize="13"
        ItemDisplayBinding="{Binding conditionName}"
        />
</Grid>

Below is my InsertEdit content page code

public partial class Overview : ContentPage
{
    public Overview()
    {
        InitializeComponent();
    }

    protected override async void OnAppearing()
    {
        base.OnAppearing();

        Quantity.Text = "Quantity : " + (await App.DbHelper.GetProductTableCount()).ToString();

        lvItems.BeginRefresh();

        List<Product> productList = await App.DbHelper.GetProductListAsync();

        lvItems.ItemsSource = productList;
        lvItems.EndRefresh();

    }

    async void OnListViewItemSelected(object sender, SelectedItemChangedEventArgs e)
    {
        if (e.SelectedItem != null)
        {
            Product product = e.SelectedItem as Product;

            var tab = this.Parent as TabbedPage;
            tab.BindingContext = new TabbedViewModel(product);
            tab.CurrentPage = tab.Children[0];

            /*await Navigation.PushAsync(new TabbedPage
            {
                BindingContext = new TabbedViewModel(product)
            });*/
        }
    }
}

Really appreciates it if someone can point me to the correct direction. I have been trying for days and the code above are the best that I can come out with. I am just lost on how to populate picker info.

1

1 Answers

0
votes

Add ProductCondition class object in Product Class and then Populate.

public class Product
{
        [PrimaryKey, AutoIncrement]
        public int id { get; set; }
        public string productCode { get; set; }
        public string description { get; set; }
        public string merchant { get; set; }
        public string remarks { get; set; }
        public ProductCondition productCondition { get; set; }            
}

Add SelectedItem in your picker

<Picker Grid.Column="2"
        Title="Select Condition" 
        x:Name="picker" 
        FontSize="13"
        ItemDisplayBinding="{Binding conditionName}"
        SelectedItem="{Binding MyItemSelected,Mode="TwoWay"}"
        />

ViewModel

private ProductCondition myItemSelected = new ProductCondition();

public ProductCondition MyItemSelected
{
  get => myItemSelected;
  set
  {
     myItemSelected = value;
     OnPropertyChanged("MyItemSelected");
  }
}

And then before you navigate

MyItemSelected = selectedProduct.productCondition;