I have a custom listview in my C# Android app, each row contains a textview, ImageView and a switch. When a Listview item is clicked, I want to turn the row's item switch on.
MainActivity:
List<TableList> list = = new List<TableList>();
list.Add(new TableList("Germany"));
list.Add(new TableList("France"));
list.Add(new TableList("Finland"));
listView.ItemClick += delegate (object sender, AdapterView.ItemClickEventArgs e)
{
string selected = t.Name;
if (selected == "France")
{
// Turn the proper switch for France row ON
}
};
ListAdapter and ListClass for the Listview:
public class ListAdapter : BaseAdapter<TableList>
{
List<TableList> items;
Activity context;
public ListAdapter(Activity context, List<TableList> items)
: base()
{
this.context = context;
this.items = items;
}
public override long GetItemId(int position)
{
return position;
}
public override TableList this[int position]
{
get { return items[position]; }
}
public override int Count
{
get { return items.Count; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = items[position];
View view = convertView;
if (view == null) // no view to re-use, create new
view = context.LayoutInflater.Inflate(Resource.Layout.CoinList, null);
view.FindViewById<TextView>(Resource.Id.CoinName).Text = item.Name;
view.FindViewById<ImageView>(Resource.Id.imageView1).SetImageResource(Resource.Drawable.n);
If item is clicked set it on
{
view.FindViewById<Switch>(Resource.Id.switch).SetOn
}
else
{
view.FindViewById<Switch>(Resource.Id.switch).SetOf
}
return view;
}
}
public class TableList
{
public string Name;
public TableList(string Name)
{
this.Name = Name;
}
}
I don't know where I should set the Switch ON (in the listView.ItemClick event or in the ListAdapter) and I don't know how to set it to ON. Please help me to do so.
Here is my demo.
You can choose one to achieve your goal. I will show you how to do this by ItemClick event:
When a Listview item is clicked, I want to turn the row's item switch on.
Because, Switch will grab the focus from ViewGroup. So, I remove the focus from Switch in the MyAdapter:
holder.ms.Focusable = false;//ms is Switch
Now, this is my ItemClick event( turn switch on while click the item):
private void MListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
var ll = e.View as LinearLayout;
var sw = ll.GetChildAt(1) as Switch;
if (sw.Checked)
{
sw.Checked = false;
adapter.changeState((int)sw.Tag,false);
}
else
{
sw.Checked = true;
adapter.changeState((int)sw.Tag, true);
}
}
As we all know, ListView has reuse problem, so, I add a bool property to control the Switch's state:
public class MyData:Java.Lang.Object {
public MyData(string p,bool b) {
this.position = p;
this.isCheck = b;
}
public string position { get; set; }
public bool isCheck { get; set; }
}
Below is changeState method:
internal void changeState(int position, bool v)
{
mitems[position].isCheck = v;
this.NotifyDataSetChanged();
}
And this is CheckedChange event:
private void Ms_CheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e)
{
var sm = sender as Switch;
Log.Error("Ms_CheckedChange", (int)sm.Tag+"");
if (e.IsChecked&&!mitems[(int)sm.Tag].isCheck)
{
mitems[(int)sm.Tag].isCheck = true;
this.NotifyDataSetChanged();
}
else if(!e.IsChecked&& mitems[(int)sm.Tag].isCheck)
{
mitems[(int)sm.Tag].isCheck = false;
this.NotifyDataSetChanged();
}
}
Related
I was wondering if there is a way to make a multi choice list view that is actually able to return the selected indexes. I've been able to do it with the pre-made multiplechoicelistview adapter but I need to be able to edit the style of it. So I need a custom listview.
This is my oncreate code a
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Options);
outList = FindViewById<ListView>(Resource.Id.outList);
var btnCheck = FindViewById<ImageButton>(Resource.Id.btnConfirm);
var btnBack = FindViewById<ImageButton>(Resource.Id.btnBack);
for (int i = 0; i < NewProfileVars.LifeStyles.Length; i++)
{
inList.Add(NewProfileVars.LifeStyles[i].Name);
}
//list contents end here
ListViewAdapter adapter = new ListViewAdapter(this, inList);
outList.Adapter = adapter;
outList.ChoiceMode = ChoiceMode.Multiple;
NewProfile main = new NewProfile();
btnCheck.Click += Confirm;
btnBack.Click += Back;
}
And here is my list view adaptor code
class ListViewAdapter: BaseAdapter<string>
{
public List<string> Items;
public Context Context;
public ListViewAdapter(Context context, List<string> items)
{
Items = items;
Context = context;
}
public override int Count
{
get { return Items.Count; }
}
public override long GetItemId(int position)
{
return position;
}
public override string this[int position]
{
get { return Items[position]; }
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View row = convertView;
if (row == null)
{
row = LayoutInflater.From(Context).Inflate(Resource.Layout.ListBox, null, false);
}
CheckBox txtName = row.FindViewById<CheckBox>(Resource.Id.cbName);
txtName.Text = Items[position];
return row;
}
}
All I need now is to figure out how that confirm button would save the things I have selected.
Thank you in advanced for the help.
I see you are using CheckBox in your ListView. You could get the Items that where Checked using something like this:
First create a class that will hold your item data and the Checked state, for the example let's call it
public class LifeStylesListItem
{
public string Name { get; set; }
public bool IsSelected { get; set; }
public LifeStylesListItem(string name)
{
Name = name;
}
}
Then modify your ListViewAdapter
Add a new private field that will hold a list of LifeStylesListItem
private List<LifeStylesListItem> _list;
Initialize the list with the Items passed in the constructor.
public ListViewAdapter(Context context, List<string> items)
{
Items = items;
_list = new List<LifeStylesListItem>();
//Your are creating a copy of your Items
foreach (var item in items)
{
_list.Add(new LifeStylesListItem(item));
}
Context = context;
}
In the GetView method subscribe to the CheckedChange event of your CheckBox. This way you will be notify when it's checked state has changed. Also you need to set the Checked Property based on the Item IsSelected value. This is necessary when the ListView will reuse your cell.
public override View GetView(int position, View convertView, ViewGroup parent)
{
View row = convertView;
if (row == null)
{
row = LayoutInflater.From(Context).Inflate(Resource.Layout.ListBox, null, false);
}
CheckBox txtName = row.FindViewById<CheckBox>(Resource.Id.cbName);
txtName.Text = _list[position].Name;
txtName.Checked = _list[position].IsSelected;
txtName.CheckedChange -= TxtName_CheckedChange;
txtName.CheckedChange += TxtName_CheckedChange;
return row;
}
Add the event handler TxtName_CheckedChange method
void TxtName_CheckedChange(object sender, CompoundButton.CheckedChangeEventArgs e)
{
//These lines are used to get the position of the control that was clicked
var obj = sender as CheckBox;
var row = obj?.Parent as View;
var parent = row?.Parent as ListView;
if (parent == null)
{
return;
}
var position = parent.GetPositionForView(row);
// Once you have the position you can get the item and change
// its IsSelected
var item = _list[position];
item.IsSelected = e.IsChecked;
}
Then a last method to add in the Adapter is the one that will return the selected Items. With the help of Linq (using System.Linq needs to be added) you can query the selected items like this.
public List<string> GetCheckedItems()
{
return _list
.Where(a => a.IsSelected)
.Select(b => b.Name)
.ToList();
}
Now in your Activity you just need to call the GetCheckedItems from the ListViewAdapter method on the Confirm button click:
private void Confirm(object sender, EventArgs e)
{
var checkedItems = adapter.GetCheckedItems();
}
Remember to change adapter as private field in your Activity
private ListViewAdapter adapter;
Hope this helps.-
I have my fragments inside view page but I would like to reload the data on the tab selected.I tried returning PositionNone in the GetItemPosition method in my FragmentPagerAdapter but it does not work.
I tried adding notifyDataSetChanged(); on tab selected but it throws nullpointer exception.
I even tried setting the viewPager.setOffscreenPageLimit
I managed to find the link :
Replace Fragment inside a ViewPager
but it is on java.
I have managed to convert most of the code to c# but gets stuck on the commented code. I am not sure how to call the listener and instantiate the class at the same time? There is a lot of similar question but unfortunately not one in Xamarin Android.
I need to do this in xamarin android. Any help will be greatly appreciated.
This is my FragmentAdapter
public class TabsFragmentPagerAdapter : FragmentPagerAdapter
{
private readonly Android.Support.V4.App.Fragment[] fragments;
static readonly int NUM_ITEMS = 2;
private readonly Android.Support.V4.App.FragmentManager FragmentManager;
private Android.Support.V4.App.Fragment mFragmentAtPos0;
private readonly ICharSequence[] titles;
public TabsFragmentPagerAdapter(Android.Support.V4.App.FragmentManager fm, Android.Support.V4.App.Fragment[] fragments, ICharSequence[] titles) : base(fm)
{
this.fragments = fragments;
this.titles = titles;
}
public override int Count
{
get
{
return fragments.Length;
}
}
public override int GetItemPosition(Java.Lang.Object objectValue)
{
if (objectValue.GetType() == typeof(startJobFrag) && mFragmentAtPos0.GetType() == typeof(jobCaptureFrag))
{
return PositionNone;
}
return PositionUnchanged;
}
public override ICharSequence GetPageTitleFormatted(int position)
{
return titles[position];
}
public override Android.Support.V4.App.Fragment GetItem(int position)
{
if (position == 0)
{
if (mFragmentAtPos0 == null)
{
//not working
}
return mFragmentAtPos0;
}
else
{
return new jobCaptureFrag();
}
}
This is my Actvity
void FnInitTabLayout()
{
var fragments = new Android.Support.V4.App.Fragment[]
{
new frag 1(),
new frag 2(),
new frag 3(),
};
//Tab title array
var titles = CharSequence.ArrayFromStringArray(new[] {
"Page 1",
"Page 2",
"Page 3",
});
var viewPager = FindViewById<ViewPager>(Resource.Id.viewpager);
//viewpager holding fragment array and tab title text
//viewPager.
viewPager.Adapter = new TabsFragmentPagerAdapter(SupportFragmentManager, fragments, titles);
// Give the TabLayout the ViewPager
tabLayout.SetupWithViewPager(viewPager);
viewPager.PageSelected += (object sender, ViewPager.PageSelectedEventArgs e) =>
{
//FnInitTabLayout();
if(e.Position == 0)
{
//handle tab click/selected
}
};
}
public interface FirstPageFragmentListener
{
void onSwitchToNextFragment();
}
Fragment
public class Fragment1: Android.Support.V4.App.Fragment
{
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your fragment here
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
// Use this to return your custom view for this Fragment
// return inflater.Inflate(Resource.Layout.YourFragment, container, false);
View view = inflater.Inflate(Resource.Layout.myview, container, false);
}
}
I managed to solve it on my own.
In My activity I called NotifyDataSetChanged() on Pageselected event
Activity
ViewPager.PageSelected += (object sender, ViewPager.PageSelectedEventArgs e) =>
{
if (e.Position == 1)
{
_pager.Adapter.NotifyDataSetChanged();
}
};
Then I changed my Adapter from FragmentPagerAdapter to FragmentStatePagerAdapter and override the GetItemPosition.
Adapter
public class TabsFragmentPagerAdapter : FragmentStatePagerAdapter
{
public override int GetItemPosition(Java.Lang.Object objectValue)
{
return PositionNone;
}
}
Refresh a specific tab - inside the Adapter
public override Android.Support.V4.App.Fragment GetItem(int position)
{
if(position == 1) //second tab selected
{
NotifyDataSetChanged();
}
return fragments[position];
}
I'm sure there's a better way to do it but this works.
Hi,
I'm struggling a bit using the ListBox.DataSource and the INotifyPropertyChanged Interface. I checked several posts about this issue already but I cannot figure out, how to update the view of a ListBox if an element of the bound BindingList is changed.
I basically want to change the color of an IndexItem after the content has been parsed.
Here the relevant calls in my form:
btn_indexAddItem.Click += new EventHandler(btn_indexAddItem_Click);
lst_index.DataSource = Indexer.Items;
lst_index.DisplayMember = "Url";
lst_index.DrawItem += new DrawItemEventHandler(lst_index_DrawItem);
private void btn_indexAddItem_Click(object sender, EventArgs e)
{
Indexer.AddSingleURL(txt_indexAddItem.Text);
}
private void lst_index_DrawItem(object sender, DrawItemEventArgs e)
{
IndexItem item = lst_index.Items[e.Index] as IndexItem;
if (item != null)
{
e.DrawBackground();
SolidBrush brush = new SolidBrush((item.hasContent) ? SystemColors.WindowText : SystemColors.ControlDark);
e.Graphics.DrawString(item.Url, lst_index.Font, brush, 0, e.Index * lst_index.ItemHeight);
e.DrawFocusRectangle();
}
}
Indexer.cs:
class Indexer
{
public BindingList<IndexItem> Items { get; }
private object SyncItems = new object();
public Indexer()
{
Items = new BindingList<IndexItem>();
}
public void AddSingleURL(string url)
{
IndexItem item = new IndexItem(url);
if (!Items.Contains(item))
{
lock (SyncItems)
{
Items.Add(item);
}
new Thread(new ThreadStart(() =>
{
// time consuming parsing
Thread.Sleep(5000);
string content = item.Url;
lock (SyncItems)
{
Items[Items.IndexOf(item)].Content = content;
}
}
)).Start();
}
}
}
IndexItem.cs
class IndexItem : IEquatable<IndexItem>, INotifyPropertyChanged
{
public int Key { get; }
public string Url { get; }
public bool hasContent { get { return (_content != null); } }
private string _content;
public string Content {
get
{
return (hasContent) ? _content : "empty";
}
set
{
_content = value;
ContentChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void ContentChanged()
{
if (this.PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Content"));
}
}
public IndexItem(string url)
{
this.Key = url.GetHashCode();
this.Url = url;
}
public override bool Equals(object obj)
{
return Equals(obj as IndexItem);
}
public override int GetHashCode()
{
return Key;
}
public bool Equals(IndexItem other)
{
if (other == null) return false;
return (this.Key.Equals(other.Key)) ||
((hasContent || other.hasContent) && (this._content.Equals(other._content)));
}
public override string ToString()
{
return Url;
}
}
Any ideas what went wrong and how to fix it? I'll appreciate any hint...
It seems to me that the control should redraw when it raises the ListChanged event for that item. This will force it to do so:
lst_index.DrawItem += new DrawItemEventHandler(lst_index_DrawItem);
Indexer.Items.ListChanged += Items_ListChanged;
private void Items_ListChanged(object sender, ListChangedEventArgs e)
{
lst_index.Invalidate(); // Force the control to redraw when any elements change
}
So why doesn't it do that already? Well, it seems that the listbox only calls DrawItem if both DisplayMember changed, and if the INotifyPropertyChanged event was raised from the UI thread. So this also works:
lock (SyncItems)
{
// Hacky way to do an Invoke
Application.OpenForms[0].Invoke((Action)(() =>
{
Items[Items.IndexOf(item)].Url += " "; // Force listbox to call DrawItem by changing the DisplayMember
Items[Items.IndexOf(item)].Content = content;
}));
}
Note that calling PropertyChanged on the Url is not sufficient. The value must actually change. This tells me that the listbox is caching those values. :-(
(Tested with VS2015 REL)
Hi I want to add pull to refresh on my apps using this component PullToResharp, The project is great but im having problem adding custom listview in fragment, does anyone here done this before help me resolve it, thanks.
here is the code
fragment
namespace ListViewPullToRefresh.Fragments
{
public class SampleListFragment : SupportListFragment
{
private IPullToRefresharpView _ptrView;
private List<TableItem> _itemHeading = new List<TableItem>();
public SampleListFragment() : base()
{
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.Inflate(Resource.Layout.nav, null, false);
}
public override void OnViewStateRestored(Bundle savedInstanceState)
{
base.OnViewStateRestored(savedInstanceState);
_itemHeading.Add(new TableItem(){Heading = "Ivan", Subheading = "Guinto"});
_itemHeading.Add(new TableItem(){Heading = "Jonathan", Subheading = "Guinto"});
_itemHeading.Add(new TableItem(){Heading = "Keneth", Subheading = "Guinto"});
if (_ptrView == null && ListView is IPullToRefresharpView)
{
_ptrView = (IPullToRefresharpView)ListView;
_ptrView.RefreshActivated += ptr_view_RefreshActivated;
}
ListView.Adapter = new HomeScreenAdapter(this, _itemHeading);
}
private void ptr_view_RefreshActivated(object sender, EventArgs e)
{
View.PostDelayed(() =>
{
if (_ptrView != null)
{
_ptrView.OnRefreshCompleted();
}
}, 2000);
}
public override void OnDestroyView()
{
if (_ptrView != null)
{
_ptrView.RefreshActivated -= ptr_view_RefreshActivated;
_ptrView = null;
}
base.OnDestroyView();
}
public override void OnResume()
{
base.OnResume();
ListView.ItemClick += ListView_ItemClick;
}
public override void OnPause()
{
base.OnPause();
ListView.ItemClick -= ListView_ItemClick;
}
void ListView_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
Toast.MakeText(Activity,e.Position+ " Clicked",ToastLength.Short).Show();
}
}
HomeScreenAdapter.cs
public class HomeScreenAdapter :BaseAdapter<TableItem>
{
public HomeScreenAdapter(Activity content, List<TableItem> items)
{
_content = content;
_items = items;
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var item = _items[position];
var view = convertView;
if (view == null)
view = _content.LayoutInflater.Inflate(Resource.Layout.CustomView, null);
view.FindViewById<TextView>(Resource.Id.Text1).Text = item.Heading;
view.FindViewById<TextView>(Resource.Id.Text2).Text = item.Subheading;
return view;
}
public override int Count
{
get { return _items.Count; }
}
public override TableItem this[int position]
{
get { return _items[position]; }
}
}
}
im getting this error
Error 1 The best overloaded method match for 'ListViewPullToRefresh.HomeScreenAdapter.HomeScreenAdapter(Android.App.Activity, System.Collections.Generic.List)' has some invalid arguments C:\Users******\Documents\Visual Studio 2013\Projects\ListViewPullToRefresh\ListViewPullToRefresh\Fragments\SampleListFragment.cs 43 32 ListViewPullToRefresh
Error 2 Argument 1: cannot convert from 'ListViewPullToRefresh.Fragments.SampleListFragment' to 'Android.App.Activity' C:\Users****\Documents\Visual Studio 2013\Projects\ListViewPullToRefresh\ListViewPullToRefresh\Fragments\SampleListFragment.cs 43 54 ListViewPullToRefresh
when i putting my custom adapter to the fragment, i get the error here ListView.Adapter = new HomeScreenAdapter(this, _itemHeading); and here public HomeScreenAdapter(Activity content, List<TableItem> items)
{
_content = content;
_items = items;
}
I get a problem when I am trying to show an AlertDialog in my adapter. It's showed many time when I want to delete an article (The first article for each category) or when I try to delete a category (Exactly when I remove a second category )
This is my code
ArticlesConfigurations.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Util;
using Android.Views;
using Android.Widget;
using SymaMobile.Core.Models;
using Vici.CoolStorage;
using SymaMobile.Droid.Adapters;
using Android.Database;
namespace SymaMobile.Droid
{
public class ArticlesConfiguration : Fragment
{
private ListView listViewCatgArticles;
private ListCategorieArticlesConfigAdapter adapterCatConfig;
private ListArticleConfigAdapter adapterArticles;
private List<CategoriesArticlesConfig> listCatgArticles;
private List<ArticlesConfig> listArticles;
private Button ajouterArticle;
private GridView gridArticles;
private ArticlesConfig art;
private TextView codeBarre;
private TextView libelle;
private CategoriesArticlesConfig categorieActuelle;
private Articles articleActuelle;
private CSList<CategoriesArticles, int> catglist;
private Spinner categorie;
private Spinner articles;
public override View OnCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View v = inflater.Inflate(Resource.Layout.fragment_configuration_articles, container, false);
listViewCatgArticles = v.FindViewById<ListView>(Resource.Id.lv_articles_fragment_configuration_articles);
ajouterArticle = v.FindViewById<Button>(Resource.Id.bt_ajouter_fragment_configuration_articles);
gridArticles = v.FindViewById<GridView>(Resource.Id.gv_articles_fragment_articles_configuration);
listCatgArticles = CategoriesArticlesConfig.List().ToList<CategoriesArticlesConfig>();
adapterCatConfig = new ListCategorieArticlesConfigAdapter(Activity, listCatgArticles);
listViewCatgArticles.Adapter = adapterCatConfig;
ajouterArticle.Click += ajouterArticle_Click;
listViewCatgArticles.ItemClick += listViewCatgArticles_ItemClick;
gridArticles.ItemClick += gridArticles_ItemClick;
return v;
}
void gridArticles_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
if (e.Position == gridArticles.Count-1)
{
Android.Util.Log.Error("Position grid", ""+e.Position);
Android.Util.Log.Error("grid Count", "" + gridArticles.Count);
AlertDialog.Builder builder = new AlertDialog.Builder(Activity);
builder.SetTitle(Resource.String.ajouter_categorie);
LayoutInflater inflater = Activity.LayoutInflater;
View v = inflater.Inflate(Resource.Layout.alertdialog_ajouter_article_configuration, null);
codeBarre = v.FindViewById<TextView>(Resource.Id.ed_code_barre_alert_dialog_ajouter_article_configuration);
libelle = v.FindViewById<TextView>(Resource.Id.tv_nom_article_alert_dialog_ajouter_article_configuration);
categorie = v.FindViewById<Spinner>(Resource.Id.sp_categories_alert_dialog_ajouter_article_configuration);
articles = v.FindViewById<Spinner>(Resource.Id.sp_articles_alert_dialog_ajouter_article_configuration);
var adapter = new ArrayAdapter<string>(Activity, Android.Resource.Layout.SimpleSpinnerDropDownItem);
catglist = CategoriesArticles.List();
for (int i = 0; i < catglist.Count; i++)
{
adapter.Add(catglist[i].Nom);
}
categorie.ItemSelected += categorie_ItemSelected;
categorie.Adapter = adapter;
codeBarre.TextChanged+=codeBarre_TextChanged;
builder.SetPositiveButton(Resource.String.ajouter, delegate
{
if (articleActuelle != null && categorieActuelle != null)
{
ArticlesConfig a = ArticlesConfig.New();
a.Article = articleActuelle;
a.CategorieArticles = categorieActuelle;
a.Save();
listArticles.Add(a);
adapterArticles.NotifyDataSetChanged();
}
});
builder.SetNegativeButton(Resource.String.annuler, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.SetView(v);
builder.Show();
}
}
void categorie_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
{
List<Articles> a = catglist[e.Position].Articles.ToList<Articles>();
var adapter = new ArrayAdapter<string>(Activity, Android.Resource.Layout.SimpleSpinnerDropDownItem);
for (int i = 0; i < a.Count; i++)
{
adapter.Add(a[i].Libelle);
}
articles.Adapter = adapter;
}
private void codeBarre_TextChanged(object sender, Android.Text.TextChangedEventArgs e)
{
if (codeBarre.Text.Length > 2)
{
articleActuelle = Articles.ReadFirst("CodeBarre ='" + codeBarre.Text + "'");
if (articleActuelle != null)
{
libelle.Text = articleActuelle.Libelle;
}
else
{
libelle.Text = "";
}
}
}
void listViewCatgArticles_ItemClick(object sender, AdapterView.ItemClickEventArgs e)
{
categorieActuelle = CategoriesArticlesConfig.Read((int)adapterCatConfig.GetItemId(e.Position));
listArticles = categorieActuelle.ArticlesConfig.ToList();
adapterArticles = new ListArticleConfigAdapter(Activity, listArticles);
gridArticles.Adapter = adapterArticles;
}
void ajouterArticle_Click(object sender, EventArgs e)
{
AlertDialog.Builder builder = new AlertDialog.Builder(Activity);
builder.SetTitle(Resource.String.ajouter_categorie);
LayoutInflater inflater = Activity.LayoutInflater;
View v = inflater.Inflate(Resource.Layout.alertdialog_ajouter_categorie_article_configuration, null);
TextView nom = v.FindViewById<TextView>(Resource.Id.ed_nom_ajouter_categorie_fragment_article_configuration);
builder.SetPositiveButton(Resource.String.ajouter, delegate
{
if (nom.Text.Length > 0)
{
CategoriesArticlesConfig c = CategoriesArticlesConfig.New();
c.Nom = nom.Text;
c.Save();
c = CategoriesArticlesConfig.ReadFirst("CategorieArticlesConfigID=" + c.CategorieArticlesConfigID);
listCatgArticles.Add(c);
adapterCatConfig.NotifyDataSetChanged();
}
});
builder.SetNegativeButton(Resource.String.annuler, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.SetView(v);
builder.Show();
}
}
}
ListCategorieArticlesConfigAdapter.cs
namespace SymaMobile.Droid.Adapters
{
class ListCategorieArticlesConfigAdapter : BaseAdapter
{
private List<CategoriesArticlesConfig> list;
private int indice;
private Activity Activity;
public ListCategorieArticlesConfigAdapter(Android.App.Activity Activity, List<CategoriesArticlesConfig> list)
: base()
{
this.Activity = Activity;
this.list = list;
}
public override int Count
{
get { return list.Count; }
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return list[position].CategorieArticlesConfigID;
}
public override Android.Views.View GetView(int position, Android.Views.View convertView, Android.Views.ViewGroup parent)
{
var view = (convertView ??
Activity.LayoutInflater.Inflate(
Resource.Layout.list_item_categories_articles_configuration,
parent,
false)) as LinearLayout;
var nom = view.FindViewById(Resource.Id.tv_nom_list_item_categories_articles_configuration) as TextView;
var modify = view.FindViewById(Resource.Id.bt_modify_list_categories_articles_configuration) as Button;
var delete = view.FindViewById(Resource.Id.bt_delete_list_categories_articles_configuration) as Button;
modify.Click += modify_Click;
indice = position;
delete.Click +=delete_Click;
nom.Text = list[position].Nom;
return view;
}
void delete_Click(object sender, EventArgs e)
{
Android.App.AlertDialog.Builder builder = new Android.App.AlertDialog.Builder(Activity);
builder.SetMessage(Resource.String.msg_supprimer);
builder.SetPositiveButton(Resource.String.oui, delegate
{
CSDatabase.ExecuteNonQuery("DELETE FROM CategoriesArticlesConfig WHERE CategorieArticlesConfigID=" + list[indice].CategorieArticlesConfigID);
list.RemoveAt(indice);
NotifyDataSetChanged();
});
builder.SetNegativeButton(Resource.String.non, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.Show();
}
void modify_Click(object sender, EventArgs e)
{
AlertDialog.Builder builder = new AlertDialog.Builder(Activity);
builder.SetTitle(Resource.String.modifier_categorie);
LayoutInflater inflater = Activity.LayoutInflater;
View v = inflater.Inflate(Resource.Layout.alertdialog_ajouter_categorie_article_configuration, null);
TextView _nom = v.FindViewById<TextView>(Resource.Id.ed_nom_ajouter_categorie_fragment_article_configuration);
_nom.Text = list[indice].Nom;
builder.SetNegativeButton(Resource.String.annuler, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.SetPositiveButton(Resource.String.modifier, delegate {
CategoriesArticlesConfig c = CategoriesArticlesConfig.ReadFirst("CategorieArticlesConfigID=" + list[indice].CategorieArticlesConfigID);
if (c != null)
{
c.Nom = _nom.Text;
c.Save();
}
list[indice].Nom = _nom.Text;
NotifyDataSetChanged();
});
builder.SetView(v);
builder.Show();
}
}
}
ListArticleConfigAdapter
namespace SymaMobile.Droid.Adapters
{
class ListArticleConfigAdapter : BaseAdapter
{
Activity context;
private List<ArticlesConfig> liste;
private int indice;
public ListArticleConfigAdapter(Activity context, List<ArticlesConfig> liste)
: base()
{
this.context = context;
this.liste = liste;
}
public override int Count
{
get { return liste.Count+1; }
}
public override long GetItemId(int position)
{
return position;
}
public override Android.Views.View GetView(int position, View convertView, ViewGroup parent)
{
var view = (convertView ??
context.LayoutInflater.Inflate(
Resource.Layout.list_item_article_configuration,
parent,
false)) as LinearLayout;
var image = view.FindViewById(Resource.Id.iv_list_item_article_configuration) as ImageView;
var nom = view.FindViewById(Resource.Id.tv_nom_article_list_item_article_configuration) as TextView;
var supprimer = view.FindViewById(Resource.Id.bt_delete_list_item_article_configuration) as Button;
Android.Util.Log.Error("Position : ", ""+position+" List Count : "+liste.Count);
if (position < liste.Count)
{
nom.Text = liste[position].Article.Libelle;
image.SetImageBitmap(Tools.ImageTools.StringToBitMap(liste[position].Article.Image));
}
else
{
nom.Text = context.Resources.GetString(Resource.String.ajouter);
image.SetImageResource(Resource.Drawable.add128x128);
supprimer.Visibility = ViewStates.Invisible;
}
indice = position;
supprimer.Click += supprimer_Click;
return view;
}
void supprimer_Click(object sender, EventArgs e)
{
Android.App.AlertDialog.Builder builder = new Android.App.AlertDialog.Builder(context);
builder.SetMessage(Resource.String.msg_supprimer);
builder.SetPositiveButton(Resource.String.oui, delegate
{
CSDatabase.ExecuteNonQuery("DELETE FROM ArticlesConfig WHERE ArticlesConfigID=" + liste[indice].ArticlesConfigID);
liste.RemoveAt(indice);
NotifyDataSetChanged();
});
builder.SetNegativeButton(Resource.String.non, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.Show();
}
public override Java.Lang.Object GetItem(int position)
{
return position;
}
}
}
thank you in advance
u have need to do this code on next activity onbackpress or
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
progressDialog.dismiss();
}
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
System.exit(0);
}
In ListCategorieArticlesConfigAdapter.GetView (), you're adding new event handlers for modify and delete, even when the view has been recycled, which means it will already have those handlers. Convert your convertView ?? check into an if/else check and do not reinitialise the handlers when convertView != null.
Modified your adapter to use view holder pattern. This should solve your issues.
class ListCategorieArticlesConfigAdapter : BaseAdapter
{
private List<CategoriesArticlesConfig> list;
private Activity Activity;
public ListCategorieArticlesConfigAdapter(Android.App.Activity Activity, List<CategoriesArticlesConfig> list)
: base()
{
this.Activity = Activity;
this.list = list;
}
public override int Count
{
get { return list.Count; }
}
public override Java.Lang.Object GetItem(int position)
{
return null;
}
public override long GetItemId(int position)
{
return list[position].CategorieArticlesConfigID;
}
public override Android.Views.View GetView(int position, Android.Views.View convertView,
Android.Views.ViewGroup parent)
{
ViewHolder vh;
var view = convertView;
if (view == null)
{
view = Activity.LayoutInflater.Inflate(Resource.Layout.list_item_categories_articles_configuration,
false);
vh = new ViewHolder(list);
vh.Initialize(view);
view.Tag = vh;
}
vh = view.Tag as ViewHolder;
vh.Bind(position);
return view;
}
private class ViewHolder : Java.Lang.Object
{
private TextView _nom;
private Button _modify;
private Button _delete;
private List<CategoriesArticlesConfig> _list;
public ViewHolder(List<CategoriesArticlesConfig> list)
{
_list = list;
}
public void Initialize(View view)
{
_nom = view.FindViewById<TextView>(Resource.Id.tv_nom_list_item_categories_articles_configuration);
_modify = view.FindViewById<Button>(Resource.Id.bt_modify_list_categories_articles_configuration);
_delete = view.FindViewById<Button>(Resource.Id.bt_delete_list_categories_articles_configuration);
}
public void Bind(int position)
{
_modify.Tag = position;
_modify.Click += modify_Click;
_delete.Click += delete_Click;
_nom.Text = _list[position].Nom;
}
void delete_Click(object sender, EventArgs e)
{
var indice = (int)(((View)sender).Tag);
Android.App.AlertDialog.Builder builder = new Android.App.AlertDialog.Builder(Activity);
builder.SetMessage(Resource.String.msg_supprimer);
builder.SetPositiveButton(Resource.String.oui, delegate
{
CSDatabase.ExecuteNonQuery("DELETE FROM CategoriesArticlesConfig WHERE CategorieArticlesConfigID=" + list[indice].CategorieArticlesConfigID);
list.RemoveAt(indice);
NotifyDataSetChanged();
});
builder.SetNegativeButton(Resource.String.non, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.Show();
}
void modify_Click(object sender, EventArgs e)
{
var indice = (int)(((View)sender).Tag);
AlertDialog.Builder builder = new AlertDialog.Builder(Activity);
builder.SetTitle(Resource.String.modifier_categorie);
LayoutInflater inflater = Activity.LayoutInflater;
View v = inflater.Inflate(Resource.Layout.alertdialog_ajouter_categorie_article_configuration, null);
TextView _nom = v.FindViewById<TextView>(Resource.Id.ed_nom_ajouter_categorie_fragment_article_configuration);
_nom.Text = _list[indice].Nom;
builder.SetNegativeButton(Resource.String.annuler, (Android.Content.IDialogInterfaceOnClickListener)null);
builder.SetPositiveButton(Resource.String.modifier, delegate
{
CategoriesArticlesConfig c = CategoriesArticlesConfig.ReadFirst("CategorieArticlesConfigID=" + list[indice].CategorieArticlesConfigID);
if (c != null)
{
c.Nom = _nom.Text;
c.Save();
}
_list[indice].Nom = _nom.Text;
NotifyDataSetChanged();
});
builder.SetView(v);
builder.Show();
}
}
}
I find a solution. Is not the best but it work fine.
Firstly, I declare a boolean variable :
bool entree;
and in GetView method :
if ((position == 0 && !entree) || (position != 0 && entree))
{
...
entree = true;
}
that's all.