How can i update Picker inside a DataTemplate

giulichajari

New member
Joined
Nov 6, 2024
Messages
2
Programming Experience
1-3
I have a DataTemplate with a list of "Tareas", which are Task to do, each elements of "Tarea" has a list of Products:

ModelTarea:
public class Tarea : INotifyPropertyChanged
{
 
 
    public ObservableCollection<Producto> Productos { get; set; }
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

This list of product is shown in a Picker, thats go good:

AssignedTasksPage.xaml:
 <ContentView Padding="10" IsVisible="{Binding IsEnCursoVisible}"    >
     <CollectionView ItemsSource="{Binding ListaTareasEnCurso}">

         <CollectionView.ItemTemplate>

             <DataTemplate>
             ....
        <!-- Picker para Selección de Productos -->
                                     <Picker x:Name="productosPicker"
                                              Title="Seleccionar productos"
                                                 TitleColor="Black"
                                             FontAttributes="Bold"
                                             BackgroundColor="LightGray"
                                             TextColor="Black"
                                            ItemsSource="{Binding Productos}"
                                             ItemDisplayBinding="{Binding producto}"
                                              SelectedIndexChanged="OnEventIndexChanged"
                                             SelectedItem="{Binding ProductoSeleccionado, Mode=TwoWay}"
                                         />
...other componenets

            </DataTemplate>
        </CollectionView.ItemTemplate>
    </CollectionView>
</ContentView>

In this page a have a button wich carries to other contentPage just to scan a qrcode or barcode, and when it obtains the result it is closed and return, an my idea is: when the code is obtained and returning to assignedtaskpage, updating the picker( the product with this barcode shoud be selected):

assignedTasksPage.xaml.cs:
protected override void OnAppearing()
    {
        base.OnAppearing();
  
        BindingContext = _viewModel;
      
        
        if (!WeakReferenceMessenger.Default.IsRegistered<QrScannedMessage>(this))
        {

            WeakReferenceMessenger.Default.Register<QrScannedMessage>(this, async (recipient, message) =>
        {
        string qrTexto = message.Value.qrText;
        string idTarea = message.Value.idCliente;
        string idT = message.Value.idT;

            var tareaSeleccionada = _viewModel.ListaTareasEnCurso.FirstOrDefault(t => t.id == idT);

            if (tareaSeleccionada != null)
            {
                
                // Buscar el producto cuyo ID coincide con el texto escaneado
                var productoEncontrado = tareaSeleccionada.Productos.FirstOrDefault(p => p.codigo.Trim() == qrTexto.Trim());

                if (productoEncontrado != null)
                {
                    DisplayAlert("ok", productoEncontrado?.producto, "ok");
                
                    _viewModel.ProductoSeleccionado = productoEncontrado;
                  
                }
                else
                {
                    await Application.Current.MainPage.DisplayAlert("Producto no encontrado", "No se encontró ningún producto con el código escaneado.", "OK");
                }
            }
        });

        }

    }

I had tried with DislpayAlert and the product is shown perfectly, but the Picker si not showing it as the selected product
 
I don't do .NET MAUI, but I find this strange. Your picker seems to be populated using this list:
XML:
ItemsSource="{Binding Productos}"
but you are trying to set the selected item ProductoSeleccionado by finding an item from a different list:
C#:
var tareaSeleccionada = _viewModel.ListaTareasEnCurso.FirstOrDefault(t => t.id == idT);
:
var productoEncontrado = tareaSeleccionada.Productos.FirstOrDefault(p => p.codigo.Trim() == qrTexto.Trim());

I would have expected this:
C#:
var productoEncontrado = tareaSeleccionada.Productos.FirstOrDefault(p => p.codigo.Trim() == qrTexto.Trim());
to be more like:
C#:
var productoEncontrado = Productos.FirstOrDefault(p => p.codigo.Trim() == qrTexto.Trim());
 
I don't do .NET MAUI, but I find this strange. Your picker seems to be populated using this list:
XML:
ItemsSource="{Binding Productos}"
but you are trying to set the selected item ProductoSeleccionado by finding an item from a different list:
C#:
var tareaSeleccionada = _viewModel.ListaTareasEnCurso.FirstOrDefault(t => t.id == idT);
:
var productoEncontrado = tareaSeleccionada.Productos.FirstOrDefault(p => p.codigo.Trim() == qrTexto.Trim());

I would have expected this:
C#:
var productoEncontrado = tareaSeleccionada.Productos.FirstOrDefault(p => p.codigo.Trim() == qrTexto.Trim());
to be more like:
C#:
var productoEncontrado = Productos.FirstOrDefault(p => p.codigo.Trim() == qrTexto.Trim());

ok, thank you for answering. Problem is that each "tarea" has a list of "Producto". Here is the code for obtaining the tasks:

obtenertareas:
 public async Task obtenerTareasC(string idAgente)
 {
     try
     {
         // URL de la API que proporciona la lista de tareas
         string apiUrl = "https://apiurl/rest-api/AgentesRetails?dtagentesRetailCursoGET=" + idAgente;

         // Crear una instancia de HttpClient
         HttpClient client = new HttpClient();

         // Realizar una solicitud HTTP GET a la API
         HttpResponseMessage response = await client.GetAsync(apiUrl);

         // Si la solicitud fue exitosa
         if (response.IsSuccessStatusCode)
         {
             try
             {
                 string jsonContent = await response.Content.ReadAsStringAsync();

                 // Deserializar la cadena JSON en una lista de objetos de tipo Tarea
                 ObservableCollection<Tarea> tareas = JsonConvert.DeserializeObject<ObservableCollection<Tarea>>(jsonContent);

                 // Asignar las tareas al campo _tareas del ViewModel


                 foreach (var tarea in tareas)
                 {

                     tarea.Productos = await ObtenerProductosPorTarea(tarea.idcliente);
                    

                     ListaTareasEnCurso.Add(tarea);
                 }

             }
             catch (Exception ex)
             {

                 Console.WriteLine("Excepción: " + ex.ToString());


             } // Leer el contenido de la respuesta como una cadena JSON

             // Mostrar el contenido JSON usando DisplayAlert


         }
         else
         {
             Application.Current.MainPage.DisplayAlert("Error", "Error en la respuesta de la API: " + response.StatusCode, "OK");
         }
     }
     catch (Exception ex)
     {
         Application.Current.MainPage.DisplayAlert("Error", "Excepción222: ", ex.Message);

     }


 }
 
Oh! I see. I missed this line:
XML:
<CollectionView ItemsSource="{Binding ListaTareasEnCurso}">

That makes sense now.
 
So in post #1, you showed us that you implemented the basics of INotifyPropertyChanged. Do you actually call OnPropertyChanged() when the setter for ProductoSeleccionado is called? E.g.
C#:
public class Tarea : INotifyPropertyChanged
{
    :
    Producto _productoSeleccionado;

    public Producto ProductoSeleccionado
   {
        get => _productoSeleccionado;

        set
        {
            _productoSeleccionado = value;
            OnPropertyChanged(nameof(ProductoSeleccionado));
        }
    }
}

(I noticed that you don't call OnPropertyChanged() for your Productos, but I don't think that is related to your problem.) You need to manually notify the framework that the property value has been changed. As I recall, there is a Roslyn based add-in or library that you can use that automates this boilerplate notification for each property, but the name is escaping me right now.
 
Not related to your problem:
C#:
HttpClient client = new HttpClient();

Please read the documentation. In most cases, you'll just want a singleton instance of this.

 
Back
Top Bottom