Access control inside ListView and reinterate through items

SaoryEmanoelle Monteiro Rodrigues 21 Reputation points
2021-06-09T20:30:04.903+00:00

Hello! I need help with this project.

What I'm trying to achieve is: I have a list with X number of items. These items will populate the listview as expected, but their fields should be changeable through the very listview.

I made a simple sketch on Paint to exemplify:

103896-exemplo.png

So, through Binding, I am already populating the fields and I can change the values or the Entries or Pickers. That's out of the way.

My main problem now is: There will be a button at the end of the view. Once I click on this button, I need to go through every item on the list and check if these entries have new values. If they do, then I'll add the item to a list and proceed.

I've done this before on asp.net using the RowDataBound and RowCommands, but I have no idea how to replicate it here on Xamarin.Forms. So, what I need to do is:

  • Click on button and use foreach to check every item on the list. Doing this, I can easily access the item value stored within the list. However, I can't access the new values, the ones on the entry/picker to check if there are new values in them. Basically, I believe I lack a sort of connection between the item and the index of the list? I don't know.

Here's what I have so far for the XAML:

  <ContentPage.Content>  
  
        <StackLayout>  
  
            <StackLayout>  
                <ListView x:Name="listViewItensHistorico" HasUnevenRows="True" ItemSelected="listViewItensHistorico_ItemSelected">  
                    <ListView.ItemTemplate>  
                        <DataTemplate>  
                            <ViewCell>  
                                <FlexLayout Margin="15" Direction="Row" Wrap="{OnIdiom Tablet=NoWrap, Phone=Wrap}">  
  
                                    <StackLayout Spacing="{OnIdiom Tablet=50, Phone=10}" Orientation="{OnIdiom Tablet=Horizontal, Phone=Vertical}">  
  
                                        <StackLayout Orientation="{OnIdiom Tablet=Vertical, Phone=Horizontal}" Spacing="{OnIdiom Tablet=10, Phone=10}" Margin="10,0">  
                                            <Label Text="Produto:" FontAttributes="Bold"></Label>  
                                            <Label Text="{Binding DescricaoProduto}"></Label>  
                                        </StackLayout>  
  
                                        <StackLayout IsVisible="{Binding MostraUN2}" Orientation="{OnIdiom Tablet=Vertical, Phone=Horizontal}" Spacing="{OnIdiom Tablet=10, Phone=10}" Margin="10,0">  
                                            <Label Text="Quantidade" FontAttributes="Bold"></Label>  
                                        </StackLayout>  
                                        <StackLayout IsVisible="{Binding MostraUN2}" Orientation="{OnIdiom Tablet=Vertical, Phone=Horizontal}" Spacing="{OnIdiom Tablet=10, Phone=10}" Margin="10,0">  
  
                                        </StackLayout>  
  
                                    </StackLayout>  
                                </FlexLayout>  
                            </ViewCell>  
                        </DataTemplate>  
                    </ListView.ItemTemplate>  
                </ListView>  
            </StackLayout>  
  
            <StackLayout FlexLayout.Basis="100%">  
                <Button Margin="{OnIdiom Tablet='0, 50'}" x:Name="btnAdicionarItens" Clicked="btnAdicionarItens_Clicked" Text="Adicionar"/>  
            </StackLayout>  
  
        </StackLayout>  
  
    </ContentPage.Content>  

And for the .CS:

   private void listViewItensHistorico_ItemSelected(object sender, SelectedItemChangedEventArgs e)  
           {  
               //Here I am just making sure I can access my object data, which I can  
               var a = e.SelectedItem as PedidoItemHistoricoModel;  
               var b = a.IdProduto;  
           }  
     
           private async void FillObjetos()  
           {  
               var historico = await PedidoItemHistoricoController.GetPedidoItemHistorico(IdPedido);  
               if (historico.Count == 0)  
               {  
                   //Não há históricos a serem exibidos  
               }  
               else  
               {  
                   listViewItensHistorico.ItemsSource = historico;  
               }  
           }  
     
     
           private void btnAdicionarItens_Clicked(object sender, EventArgs e)  
           {  
               var listaItens = listViewItensHistorico.ItemsSource as IList<PedidoItemHistoricoModel>;  
               foreach(var item in listaItens)  
               {  
                   //I'm stuck here  
               }  
           }  
Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,328 questions
0 comments No comments
{count} votes

Accepted answer
  1. Leon Lu (Shanghai Wicresoft Co,.Ltd.) 73,371 Reputation points Microsoft Vendor
    2021-06-10T03:58:34.267+00:00

    Hello,​

    Welcome to our Microsoft Q&A platform!

    You can try to achieve it MVVM, then whatever you changed in the entry, your content in entry will be add to the model automatically. I add some content in the Entry, Then click the button to execute the command in the ViewModel. We can get all the content in all entries like following screenshot. When I add model, I did not add any names to the ObservableCollection

    104073-image.png 103986-image.png

    So, you can create new page to use my code to make a test. I do not completely use your layout, I write a layout by your design image.

       <?xml version="1.0" encoding="utf-8" ?>  
       <ContentPage xmlns="http://xamarin.com/schemas/2014/forms"  
                    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"  
                    x:Class="ListviewControlDemo.MainPage">  
    
           <ContentPage.Content>  
    
               <StackLayout>  
    
                   <StackLayout>  
                       <ListView x:Name="listViewItensHistorico" HasUnevenRows="True" ItemsSource="{Binding Items}" ItemSelected="listViewItensHistorico_ItemSelected">  
                           <ListView.ItemTemplate>  
                               <DataTemplate>  
                                   <ViewCell>  
                                       <FlexLayout Margin="15" Direction="Row" Wrap="{OnIdiom Tablet=NoWrap, Phone=Wrap}">  
    
                                           <StackLayout Spacing="{OnIdiom Tablet=50, Phone=10}" Orientation="{OnIdiom Tablet=Horizontal, Phone=Vertical}">  
    
                                               <StackLayout Orientation="{OnIdiom Tablet=Vertical, Phone=Horizontal}" Spacing="{OnIdiom Tablet=10, Phone=10}" Margin="10,0">  
                                                   <Label Text="{Binding ID}"/>  
    
                                                   <StackLayout Orientation="Horizontal">  
                                                       <Label Text="Produto:" FontAttributes="Bold"></Label>  
                                                       <Entry Text="{Binding Name}" WidthRequest="90"></Entry>  
                                                   </StackLayout>  
                                                   <StackLayout Orientation="Horizontal">  
                                                       <Label Text="Description:" FontAttributes="Bold"></Label>  
                                                       <Picker SelectedItem="{Binding Description}" WidthRequest="90">  
                                                           <Picker.ItemsSource>  
                                                               <x:Array Type="{x:Type x:String}">  
                                                                   <x:String>Baboon</x:String>  
                                                                   <x:String>Capuchin Monkey</x:String>  
                                                                   <x:String>Blue Monkey</x:String>  
                                                                   <x:String>Squirrel Monkey</x:String>  
                                                                   <x:String>Golden Lion Tamarin</x:String>  
                                                                   <x:String>Howler Monkey</x:String>  
                                                                   <x:String>Japanese Macaque</x:String>  
                                                               </x:Array>  
                                                           </Picker.ItemsSource>  
    
                                                       </Picker>  
                                                   </StackLayout>  
    
                                               </StackLayout>  
    
                                               <!--<StackLayout IsVisible="{Binding MostraUN2}" Orientation="{OnIdiom Tablet=Vertical, Phone=Horizontal}" Spacing="{OnIdiom Tablet=10, Phone=10}" Margin="10,0">  
                                                   <Label Text="Quantidade" FontAttributes="Bold"></Label>  
                                               </StackLayout>  
                                               <StackLayout IsVisible="{Binding MostraUN2}" Orientation="{OnIdiom Tablet=Vertical, Phone=Horizontal}" Spacing="{OnIdiom Tablet=10, Phone=10}" Margin="10,0">  
    
                                               </StackLayout>-->  
    
                                           </StackLayout>  
                                       </FlexLayout>  
                                   </ViewCell>  
                               </DataTemplate>  
                           </ListView.ItemTemplate>  
                       </ListView>  
                   </StackLayout>  
    
                   <StackLayout FlexLayout.Basis="100%">  
                       <Button Margin="{OnIdiom Tablet='0, 50'}" x:Name="btnAdicionarItens" Command="{Binding MyCommand}" Text="Adicionar"/>  
                   </StackLayout>  
    
               </StackLayout>  
    
           </ContentPage.Content>  
    
       </ContentPage>  
    

    Here is layout's background code.

       public partial class MainPage : ContentPage  
           {  
               public MainPage()  
               {  
                   InitializeComponent();  
                   this.BindingContext = new MyViewModel();  
               }  
    
               private void listViewItensHistorico_ItemSelected(object sender, SelectedItemChangedEventArgs e)  
               {  
    
               }  
    
               private void btnAdicionarItens_Clicked(object sender, EventArgs e)  
               {  
    
               }  
           }  
    

    Here is my MyViewModel.cs, I use ObservableCollection to contains items, then add empty MyModel.

       public class MyViewModel  
           {  
               public  ObservableCollection<MyModel> Items { get; set; }  
               public ICommand MyCommand { protected set; get; }  
               public MyViewModel()  
               {  
                   Items = new ObservableCollection<MyModel>();  
                   Items.Add(new MyModel() { ID = 1 }) ;  
                   Items.Add(new MyModel() { ID = 2 });  
                   Items.Add(new MyModel() { ID = 3 });  
                   Items.Add(new MyModel() { ID = 4 });  
                   Items.Add(new MyModel() { ID = 5 });  
                   Items.Add(new MyModel() { ID = 6 });  
                   string str="";  
                   MyCommand = new Command(() =>  
                   {  
    
                       foreach (MyModel item in Items)  
                       {  
                           str += item.Name;  
                       }  
                       Console.WriteLine(str);  
    
                   } );  
               }  
           }  
    

    Here is MyModel.cs, I acheve the INotifyPropertyChanged interface, if the value of properties be changed, it will update ASAP in the ObservableCollection.

       using System;  
       using System.Collections.Generic;  
       using System.ComponentModel;  
       using System.Text;  
    
       namespace ListviewControlDemo  
       {  
           public class MyModel: INotifyPropertyChanged  
           {  
               public string MyProperty { get; set; }  
    
               public int ID { get; set; }  
    
               string name;  
               public string Name  
               {  
                   set  
                   {  
                       if (name != value)  
                       {  
                           name = value;  
                           OnPropertyChanged("Name");  
    
                       }  
                   }  
                   get  
                   {  
                       return name;  
                   }  
               }  
    
               // public string Image { get; set; }  
               string description;  
               public string Description  
               {  
                   set  
                   {  
                       if (description != value)  
                       {  
                           description = value;  
                           OnPropertyChanged("Description");  
    
                       }  
                   }  
                   get  
                   {  
                       return description;  
                   }  
               }  
    
               public event PropertyChangedEventHandler PropertyChanged;  
    
               protected virtual void OnPropertyChanged(string propertyName)  
               {  
                   PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));  
               }  
           }  
       }  
    

    =======================
    Update========================

    After I type down the values and click the button, I need to make a multiplication depending on the chosen picker index. If I choose index 0, I'll multiply it by 2. If I chose the second index I'll multiply it by 5.

    Now this is where I am stuck again because I don't quite understand how to check which index of my picker is selected to procceed with said multiplication :(

    I did this already but with only one item at a time in a single view. I don't know how to do the same now for each item using Binding :(

    You can get the all the item in the Command, for MVVM, we can control the model directly(get the picker selectitem index by model). You just need to change two places.

    Firstly, change the Picker binding value in XAML from SelectedItem to SelectedIndex.

       <StackLayout Orientation="Horizontal">  
                                                       <Label Text="Description:" FontAttributes="Bold"></Label>  
                                                       <Picker SelectedIndex="{Binding Description}" WidthRequest="90">  
                                                           <Picker.ItemsSource>  
                                                               <x:Array Type="{x:Type x:String}">  
                                                                   <x:String>Baboon</x:String>  
                                                                   <x:String>Capuchin Monkey</x:String>  
                                                                   <x:String>Blue Monkey</x:String>  
                                                                   <x:String>Squirrel Monkey</x:String>  
                                                                   <x:String>Golden Lion Tamarin</x:String>  
                                                                   <x:String>Howler Monkey</x:String>  
                                                                   <x:String>Japanese Macaque</x:String>  
                                                               </x:Array>  
                                                           </Picker.ItemsSource>  
    
                                                       </Picker>  
                                                   </StackLayout>  
    
                                               </StackLayout>  
    

    Then open your command in the viewModel. Get the selectIndex by Model directly, then handle it by index.

       MyCommand = new Command(() =>  
                   {  
    
                       foreach (MyModel item in Items)  
                       {  
                           //str += item.Name;  
                           var nameValue=int.Parse(item.Name);  
                           if (item.Description==0)  
                           {  
                               item.Name = (nameValue * 2).ToString();  
                           }  
                           else if (item.Description == 1)  
                           {  
                               item.Name = (nameValue * 5).ToString();  
                           }  
                       }  
                       //Console.WriteLine(str);  
    
                   } );  
    

    Here is running screenshot when click Button.

    Before click the button. 105647-image.png After click the Button 105648-image.png

    Best Regards,

    Leon Lu


    If the response is helpful, please click "Accept Answer" and upvote it.

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


0 additional answers

Sort by: Most helpful