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); } 
  • Los atributos personalizados de monodroid / xamarin están vacíos usando ObtainStyledAttributes
  • Reproducir video en Android usando Xamarin
  • Cómo crear un DialogFragment personalizado al 100%
  • Inicie una actividad desde una pantalla de Preferencia
  • Formularios de Xamarin Android Aplicación no obtener DeviceToken Parse SDK
  • Visual Studio no reconoce la función BindingInflate de MvxFragment
  • Diseño personalizado para DialogFragment OnCreateView vs. OnCreateDialog
  • Icono de aplicación Crear una información de superposición (número)?
  • Mono para macros de preprocesador de Android
  • ParseInstallation.SaveAsync () que causa UnhandledException en formularios Xamarin Android
  • F # en Mono para Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.