Monodroid – Manejo Haga clic en eventos dentro de las filas ListAdapter

Tengo un ListView con un ArrayAdapter fijado a él, y cada fila en el adaptador contiene cuatro botones que necesitan recibir y manejar acontecimientos del tecleo. Normalmente en Android llamaría a SetOnClickListener en cada botón cuando SetOnClickListener la célula, pero Mono da la capacidad de fijar los encargados del acontecimiento para el acontecimiento del Click lugar de otro. Parece que hay algo de extraño a esto en Mono, sin embargo, porque me encuentro con uno de los dos problemas dependiendo de dónde establecí el manejador de eventos.

ArrayAdapter GetView Ejemplo 1:

 View tweetCell = convertView; if (tweetCell == null) { tweetCell = ((LayoutInflater)Context.GetSystemService (Context.LayoutInflaterService)).Inflate (Resource.Layout.TweetCell, null); tweetCell.FindViewById (Resource.Id.btn_moveTweet).Click += (object sender, EventArgs e) => MoveTweet (GetItem(position)); tweetCell.FindViewById (Resource.Id.btn_unfavoriteTweet).Click += (object sender, EventArgs e) => UnfavoriteTweet (GetItem(position)); tweetCell.FindViewById (Resource.Id.btn_hideTweet).Click += (object sender, EventArgs e) => HideTweet (GetItem(position)); tweetCell.FindViewById (Resource.Id.btn_shareTweet).Click += (object sender, EventArgs e) => ShareTweet (GetItem(position)); } 

Aquí, mi controlador de eventos sólo se establece una vez por botón (bueno!), Pero el valor de la position es incorrecto la mayor parte del tiempo. Me pregunto si la conversión de Mono a Android está causando que GetItem(position) utilice el mismo valor para la position cada vez (el valor que la position se establece cuando la célula se crea por primera vez). Este código funcionaría totalmente bien en Android normal.

ArrayAdapter GetView Ejemplo 2:

 View tweetCell = convertView; if (tweetCell == null) { tweetCell = ((LayoutInflater)Context.GetSystemService (Context.LayoutInflaterService)).Inflate (Resource.Layout.TweetCell, null); } tweetCell.FindViewById (Resource.Id.btn_moveTweet).Click += (object sender, EventArgs e) => MoveTweet (GetItem(position)); tweetCell.FindViewById (Resource.Id.btn_unfavoriteTweet).Click += (object sender, EventArgs e) => UnfavoriteTweet (GetItem(position)); tweetCell.FindViewById (Resource.Id.btn_hideTweet).Click += (object sender, EventArgs e) => HideTweet (GetItem(position)); tweetCell.FindViewById (Resource.Id.btn_shareTweet).Click += (object sender, EventArgs e) => ShareTweet (GetItem(position)); 

Este método hace que el evento de clic se dispare para la position correcta, pero establece un nuevo controlador de eventos cada vez que se recicla la fila. Esto hace que los eventos de clic para muchas filas al mismo tiempo. Una solución para este método parecería ser mantener referencias a los controladores de eventos y eliminarlos antes de volver a establecerlos en GetView , pero esto parece extremadamente poco elegante.

¿Hay un mejor método para manejar los eventos de clic dentro de los elementos de ListView en Monodroid?

Sé que es un viejo hilo, pero tiene un montón de votos y todavía está marcado como sin respuesta

¡Es lógico que los escenarios que describas sucedan! No tiene nada que ver con mono en absoluto. Tiene que ver con la conversión. Esto es lo que dice la documentación en convertview:

ConvertView – La vista antigua para reutilizar, si es posible. Nota: Debe comprobar que esta vista no es nula y de un tipo apropiado antes de usar. Si no es posible convertir esta vista para mostrar los datos correctos, este método puede crear una vista nueva.

Ejemplo 1: En su primer ejemplo, el convertiver será nulo la primera vez y los eventos se establecerán. A continuación, la próxima vez que se llama al método GetView , la conversión puede o no ser nula. ¡Si no es null utilizará la visión vieja con los acontecimientos todavía atados! ¡Esto significa que el evento con el parámetro de posición sigue siendo de una vista anterior!

Ejemplo 2: Este ejemplo funcionará como se esperaba pero no es muy eficiente como usted mencionó. Tiene que localizar los controles cada vez que se llama al método FindViewById .

Solución: La solución para este problema de rendimiento es implementar el patrón del espectador.

Primero crea una clase que mantenga sus vistas:

 private class MyViewHolder : Java.Lang.Object { public Button MoveTweet { get; set; } public Button ShareTweet { get; set; } public Button UnfavoriteTweet { get; set; } public Button HideTweet { get; set; } } 

Ahora puede utilizar este visor en su código

 public override View GetView (int position, View convertView, ViewGroup parent) { MyViewHolder holder; var view = convertView; if(view != null) holder = view.Tag as MyViewHolder; if (holder == null) { holder = new MyViewHolder (); view = activity.LayoutInflater.Inflate (Resource.Layout.OptimizedItem, null); holder.MoveTweet = view.FindViewById<Button> (Resource.Id. btn_moveTweet); holder.ShareTweet = view.FindViewById<Button> (Resource.Id. btn_shareTweet); holder.UnfavoriteTweet = view.FindViewById<Button> (Resource.Id. btn_unfavoriteTweetTweet); holder.HideTweet = view.FindViewById<Button> (Resource.Id. btn_hideTweet); view.Tag = holder; } holder.MoveTweet.Click += (object sender, EventArgs e) => MoveTweet (GetItem(position)); holder.UnfavoriteTweet.Click += (object sender, EventArgs e) => UnfavoriteTweet (GetItem(position)) holder.HideTweet.Click += (object sender, EventArgs e) => HideTweet (GetItem(position)); holder.FavoriteTweet.Click += (object sender, EventArgs e) => ShareTweet (GetItem(position)); return view; } 

Para obtener más información sobre este check out: https://blog.xamarin.com/creating-highly-performant-smooth-scrolling-android-listviews/

Tuve problemas similares también. Aparentemente, voy a evitar la solución 2. Además, observo el problema en la solución 1 sólo sucedió en Android 2.3.

Así arreglé el problema.

Sigo una referencia a la ListView en el adaptador, por ejemplo _listView . Entonces, en su método GetItem() (no pierda la variable de position , su valor es un misterio), llame a _listView.GetPositionForView((View)sender) para obtener la posición correcta.

Pruebe con este código:

  void OnListItemClick(object sender, AdapterView.ItemClickEventArgs e) { var listView = sender as ListView; var item = items[e.Position]; //init your data... tweetCell.FindViewById (Resource.Id.btn_moveTweet).Click += (object sender, EventArgs e) => MoveTweet (item); } 
  • No se puede implementar Xamarin aplicación correctamente
  • Cómo mostrar MessageBox en Monodroid
  • MessageDialog se cierra inesperadamente con Facebook SDK para Android
  • Rotar la imagen en el centro no va lisa (Monodroid)
  • ¿Qué podría estar causando el error "OutputPath propiedad no está establecida para proyecto ProjectName.csproj" en mi proyecto MonoDevelop
  • ¿Cómo detectar la salida de la aplicación en android?
  • MonoDroid VS Java en el desarrollo de Android?
  • OnConfigurationChanged no se llama en mono android
  • "Esperando dispositivo" al depurar en el teléfono
  • Prevent Orientation change in Xamarin Aplicación para Android
  • Silverlight / Moonlight en dispositivos Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.