0

因此,我一直在使用复选框的listview查看应用程序,我注意到当我选择一个项目时,当我向下滚动第一个项目时,在向下滚动完整页面后,也会选中该复选框。我有一种感觉,这是由于重新查看意见,但我很好奇这个解决方案。我曾尝试添加一个视图,但这并没有解决问题。只是想知道我错过了什么。代码适配器上的getview低于:带有复选框的列表视图正在检查多个复选框

 public override Android.Views.View GetView(int position, Android.Views.View convertView, ViewGroup parent) 
     { 
      Android.Views.View view = convertView; 
      if (view == null) 
      { 
       view = context.LayoutInflater.Inflate(Resource.Layout.GroupTimeTrackerTemplate, parent, false); 
      } 
      tblWorkers item = this[position]; 

      view.FindViewById<TextView>(Resource.Id.UserNameTextView).Text = this[position].nWorkerFirstname + " " + this[position].nWorkerLastname; 
      view.FindViewById<TextView>(Resource.Id.StatusTextView).Text = this[position].nStatusShort; 
      view.FindViewById<TextView>(Resource.Id.UserRoleTextView).Text = this[position].nTitle; 
      CheckBox chkSelect = view.FindViewById<CheckBox>(Resource.Id.ChkSelect); 
      chkSelect.Tag = item.nWorkerFirstname + " " + item.nWorkerLastname; 

      chkSelect.SetOnCheckedChangeListener(null); 
      chkSelect.SetOnCheckedChangeListener(new CheckChangeListener(this.context)); 
      return view; 
     } 

     private class CheckChangeListener : Java.Lang.Object, CompoundButton.IOnCheckedChangeListener 
     { 

      private Activity activity; 

      public CheckChangeListener(Activity activity) 
      { 
       this.activity = activity; 
      } 

      public void OnCheckedChanged(CompoundButton buttonView, bool isChecked) 
      { 
       if (isChecked) 
       { 
        string name = (string)buttonView.Tag; 
        string text = string.Format("{0} Checked.", name); 
        Toast.MakeText(this.activity, text, ToastLength.Short).Show(); 
       } 
      } 
     } 

回答

1

我最终找到了一个解决方案,该解决方案拥有一个可以与我的动态模型数据一起工作的View Holder。这对我下面的工作是解决方案!这三个要点是业务逻辑对象有一个布尔值来保存被检查的项目和视图持有者帮助性能,最后,因为视图的循环,你不能可靠地使用点击事件中的列表[位置],所以我使用包装!

查看持有人:

private class MyViewHolder : Java.Lang.Object 
    { 
     public TextView txtName; 
     public TextView txtStatus; 
     public TextView txtTitle; 
     public CheckBox chkItem; 

    } 

适配器GetView:对于复选框,包装和阵列

public override Android.Views.View GetView(int position, Android.Views.View convertView, ViewGroup parent) 
    { 

     var item = list[position]; 
     Android.Views.View view = convertView; 
     MyViewHolder holder; 
     if (convertView == null) 
     { 
      holder = new MyViewHolder(); 
      view = context.LayoutInflater.Inflate(Resource.Layout.GroupTimeTrackerTemplate, null); 
      holder.chkItem = view.FindViewById<CheckBox>(Resource.Id.ChkSelect); 
      holder.txtName = view.FindViewById<TextView>(Resource.Id.UserNameTextView); 
      holder.txtStatus = view.FindViewById<TextView>(Resource.Id.StatusTextView); 
      holder.txtTitle = view.FindViewById<TextView>(Resource.Id.UserRoleTextView); 
      view.Tag = holder; 
     } 
     else 
     { 
      holder = view.Tag as MyViewHolder; 

     } 
     holder.chkItem.Checked = item.StatusSelected; 
     if (holder.chkItem.Checked) 
     { 
      holder.chkItem.Enabled = false; 
     } 
     else 
     { 
      holder.chkItem.Enabled = true; 
     } 
     holder.chkItem.Tag = new MyWrapper<int>(position); 
     holder.txtName.Text = item.nWorkerFirstname + " " + item.nWorkerLastname; 
     holder.txtStatus.Text = item.nStatusShort; 
     holder.txtTitle.Text = item.nTitle; 
     holder.chkItem.Click -= HolderChkItemClick; 
     holder.chkItem.Click += HolderChkItemClick; 
     if (statoChk[position] == 0) 
     { 
      holder.chkItem.Checked = false; 
     } 
     else 
     { 
      holder.chkItem.Checked = true; 
     } 


     return view; 
    } 

Click事件:

tblWorkers OrigSel = null; 
    void HolderChkItemClick(object sender, EventArgs e) 
    { 
     var chk = sender as CheckBox; 
     int pos = ((MyWrapper<int>)chk.Tag).value; 
     tblWorkers selectedWorker = list[pos]; 
     if (Vm.SelectedWorker == null) 
     { 
      OrigSel = selectedWorker; 
      IntentManager.Instance.OriginalSelectedWorker = OrigSel; 
      Vm.GroupTimeTrackerStatusType = OrigSel.nStatusShort; 
     } 
     Vm.SelectedWorker = selectedWorker; 
     if (chk.Checked) 
     { 
      if (selectedWorker.nStatusShort == OrigSel.nStatusShort) 
      { 
       statoChk[pos] = 1; 
       Vm.GroupTimeList.Add(selectedWorker); 
      } 
      else 
      { 
       statoChk[pos] = 0; 
       chk.Checked = false; 
       Toast.MakeText(context, "Please Select Workers with the Same Time Status. Current Status : " + OrigSel.nStatusShort, ToastLength.Long).Show(); 
      } 
     } 
     else 
     { 
      statoChk[pos] = 0; 
      Vm.GroupTimeList.Remove(selectedWorker); 
      if (Vm.GroupTimeList.Count == 0) 
      { 
       Vm.SelectedWorker = null; 
       OrigSel = null; 
       IntentManager.Instance.OriginalSelectedWorker = null; 
       Vm.GroupTimeTrackerStatusType = ""; 
      } 
     } 


    } 

    public class MyWrapper<T> : Java.Lang.Object 
    { 
     private T _value; 
     public MyWrapper(T managedValue) 
     { 
      _value = managedValue; 
     } 
     public T value { get { return _value; } } 
    } 


    int[] statoChk; 
    public int[] StatoCheck 
    { 
     get { return statoChk; } 
     set { statoChk = value; } 
    } 
0

虽然我不亲自走过Xamarin开发的Android我有Android的知识,让你在正确的方向。

正如您正确指出ListView中的行被回收。问题在于,当您滚动时,将调用OnCheckedChange方法,并且由于它将其循环的行传递到未选中的新行的位置,但由于它具有与之前选择的行相同的索引,改变它的价值。

例如,如果选中索引为5的方框,然后向下滚动,则新行将变为索引为5的行,因此它会更改其状态。

这是Android上的一个常见问题。为了解决这个问题,首先你需要一个数据结构来保存哪些行已经被检查过,方法是将它存储在一张地图或一个列表中。

然后在您的GetView中,确保您将复选框状态设置为该位置的内容。

+0

我已经做了Java和C#,他们都非常类似的,虽然Xamarin并不是很多例子。令人费解的是,我使用的是我传入的实际列表,这是ObervableCollection,所以位置不应该成为问题,但我想是的。你能举一个Java例子吗? – yams

0

@Ivan Alburquerque是对的,这是由于Android回收列表中的视图。您应该始终根据数据源的位置在GetView方法上设置复选框的值。 为了避免你在这里编写的所有重复代码,我建议你使用像MvvmCross(https://github.com/mvvmcross/mvvmcross)这样的MVVM框架,它可以为你做所有事情,而你需要编写的代码将少得多。 玩得开心。

+0

我已经在使用MVVM Light! – yams

+0

那么为什么你手动设置值,但不只是绑定到源,然后将CheckBox的状态绑定到ViewModel中的值? – Ilber

+0

我绑定到源,但业务逻辑的自定义性质强制我不得不手动执行此操作。 – yams