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

相關問題