From itemclick method in adapter how to change textview in the activity - c#

I have a simple activity which textview and listview. My list view use custom adapter to display data also in the adapter i have itemClick method. I would like to change textview after clicking the list item. My problem is I don't know how to find the text view from list adapter? I'll try something like this:
TextView TeamSelect = (TextView)activity.FindViewById(Resource.Id.tvSelectPlayers);
TeamSelect.SetText("Players", TextView.BufferType.Normal);
but this give me an error:
System.NullReferenceException: Object reference not set to an instance of an object
Here is my adapter:
public HomePlayersAdapter(Activity context)
{
mInflater = LayoutInflater.From(context);
mSelectedItemsIds = new SparseBooleanArray();
this.context = context;
public override int Count //return number of items in the list
{
get { return homePlayers.Count; }
}
public override Java.Lang.Object GetItem(int position)
{
return position;
}
public Player GetObject(int position)
{
return this.homePlayers.ElementAt(position);
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
var y = (itemPos.IndexOf(position) + 1);
var item = homePlayers[position];
if (convertView == null || holder == null)
{
convertView = mInflater.Inflate(Resource.Layout.RowPlayers, null);
holder = new ViewHolder();
holder.playerName = convertView.FindViewById<TextView>(Resource.Id.tvRow); //set holder label with label list id in the view
convertView.Tag = (holder);
}
else
{
holder = (ViewHolder)convertView.Tag;
}
holder.playerName.SetText(item.firstName + " " + item.lastName, TextView.BufferType.Normal);//set data label
holder.playerName.TextSize = 30;
if (clickCount >= 15)
{
subs = 1;
Android.Widget.Toast.MakeText(context, "ok", Android.Widget.ToastLength.Short).Show();
}
else
{
subs = 0;
}
y = (itemPos.IndexOf(position) + 1);
if (itemPos.Contains(position))
{
holder.playerName.SetTextColor(mInflater.Context.Resources.GetColor(Resource.Drawable.green));
holder.playerName.SetText(y + ". " + item.firstName + " " + item.lastName, TextView.BufferType.Normal);//set data label
}
else
{ holder.playerName.SetTextColor(mInflater.Context.Resources.GetColor(Resource.Drawable.white));
}
return convertView;
}
public void itemClick(int position)
{
if (!itemPos.Contains(position))
{
clickCount++;
var selectFixtureActivity = new Intent(context, typeof(SelectPlayers));
selectFixtureActivity.PutExtra("clickCount", clickCount);
holder.playerName.SetTextColor(mInflater.Context.Resources.GetColor(Resource.Drawable.green));
itemPos.Add(position);
NotifyDataSetChanged();
insertPlayer(position);
}
else
{
clickCount--;
var selectFixtureActivity = new Intent(context, typeof(SelectPlayers));
selectFixtureActivity.PutExtra("clickCount", clickCount);
holder.playerName.SetTextColor(mInflater.Context.Resources.GetColor(Resource.Drawable.white));
deletePlayer(position);
int po = itemPos.IndexOf(position);
itemPos.RemoveAt(po);
NotifyDataSetChanged();
class ViewHolder : Java.Lang.Object
{
public TextView playerName;
}
And my activity:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.SelectPlayer);
homeListAdapter = new HomePlayersAdapter(this);
listView = FindViewById<ListView>(Resource.Id.lvSelectPlayers);
TextView TeamSelect = FindViewById<TextView>(Resource.Id.tvSelectPlayer);
listView.Adapter = homeListAdapter;
listView.ChoiceMode = ChoiceMode.Multiple;
this.listView.ChoiceMode = ChoiceMode.Multiple;
var nameHome = Intent.GetStringExtra("nameHome");
var clickCount = Intent.GetStringExtra("clickCount");
TextView homeTeam = (TextView)FindViewById(Resource.Id.tvHomeTeam);
homeTeam.SetText(nameHome, Button.BufferType.Normal);
this.listView.ItemClick += (sender, e) =>
{
homeListAdapter.itemClick(e.Position);
}
I tried do that in different way: I send clickCount variable to the activity and there in ItemClick method i tried change the text view, but clickCount var on the begining is send to the acticity but when ItemClick method finish clickCount change value to null.How can i solve this problem?

You should not access the Activity directly from the Adapter. You should set a listener on the adapter (the listener can be the Activity). This is based on the Observer pattern. It decouples the components and promotes re-usability. Then the Activity, when called, can modify its own Text View.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_layout);
ListView myListView = (ListView)findViewById(R.id.your_list);
final TextView myTextView = (TextView)findViewById(R.id.your_text);
YourAdapter adapter = new YourAdapter();
adapter.setListener(new CustomListener() { // You write this method in your adapter
#Override
public void onItemClicked(Item clickedItem) {
myListView.setText( clickedItem.toString() );
}
});
}
Or if you aren't doing anything special in the custom adapter, you can always use the built in list view listener.
myListView.setOnItemClickListener( new OnItemClick() { // This is not onClick, but onItemClick
#Override
public void onItemClicked(AdapterView<?> parent, View view, int position, long id) {
Object clickedItem = parent.getItemAtPosition(position);
myTextView.setText( clickedItem.toString() );
}
});

Related

How to Use ArrayAdapter with Multiple Textview columns in listView Xamarin Android

I have listview with 4 columns like ItemLookupCode,Quantity,Description,Price
I am adding full code i am sorting list on button click.
i have issue in following Populate() to call 4 textview
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.PriceCheckList);
List<string> list = new List<string>();
foreach (crItem item in listObject)
{
list.Add(item.ItemLookupCode);
list.Add(Convert.ToString(item.Quantity));
list.Add(item.Description);
list.Add(Convert.ToString(item.Price));
}
spacecrafts = list.ToArray();
this.InitializeViews();
this.SortData(ascending);
this.ascending = !ascending;
}
SortBtnItemLookupCode.Click += sortBtn_Click;
void sortBtn_Click(object sender, EventArgs e)
{
SortData(ascending);
this.ascending = !ascending;
}
private void InitializeViews()
{
listView = FindViewById<ListView>(Resource.Id.listView);
SortBtnItemLookupCode = FindViewById<Button>(Resource.Id.SortBtnItemLookupCode);
}
private void Populate()
{
ArrayAdapter adapter = new ArrayAdapter<string>(this, Resource.Layout.PriceCheckListTemplate, Resource.Id.lblItemLookupCode, spacecrafts);
listView.SetAdapter(adapter);
}
private void SortData(bool asc)
{
if (asc)
{
Array.Sort(spacecrafts);
}
else
{
Array.Reverse(spacecrafts);
}
Populate();
}
}
I want to assign all above 4 object to Textview but currently ArrayAdapter accept only one Textview like i have use below Resource.Id.lblItemLookupCode but How i can assign 4 object to 4 columns Textview in ArrayAdapter
Help much appreciated
Thanks in advance
Try create model class to define data for the listView's item, then customize a custom Adapter to populate the data.
Check the code:
public class MainActivity : AppCompatActivity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
string[] items = new string[] { "Vegetables", "Fruits", "Flower Buds", "Legumes", "Bulbs", "Tubers" };
List<CustomModel> list = new List<CustomModel>();
//add data
CustomAdapter adapter = new CustomAdapter(list);
ListView listview_ = FindViewById<ListView>(Resource.Id.listview_);
listview_.SetAdapter(adapter);
}
}
public class CustomModel
{
public string Value1 { get; set; }
...
}
public class CustomAdapter : BaseAdapter<CustomModel>
{
List<CustomModel> list = new List<CustomModel>();
public _Adapter(List<CustomModel> list)
{
this.list = list;
}
public override CustomModel this[int position]
{
get
{
return list[position];
}
}
public override int Count
{
get
{
return list.Count;
}
}
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
var view = convertView;
view = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.layout1, parent, false);
//specify value to the each textView
var textview = view.FindViewById<TextView>(Resource.Id.text_1);
textview.Text = list[position].Value1;
...
return view;
}
}

Create listview with button using Xamarin and SQL Server

I have created a project in which I am retrieving data from the database and display it into a ListView. See image below.
Here is the code for retrieving data for the ListView
public class MainActivity : Activity
{
public static Context context;
public static List<UserInfo> UserInfoList = new List<UserInfo>();
public static ListView ListView;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
SetContentView (Resource.Layout.Main);
ListView = FindViewById<ListView>(Resource.Id.Listview);
GetList list = new GetList();
list.Execute();
}
public class GetList : AsyncTask
{
Context con;
protected override Java.Lang.Object DoInBackground(params Java.Lang.Object[] #params)
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient( );
var _WebApiUrl = string.Format("URL");
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage messge = client.GetAsync(_WebApiUrl).Result;
var Return_EventList = messge.Content.ReadAsStringAsync().Result;
var EventList = JsonConvert.DeserializeObject<List<UserInfo>>(Return_EventList);
foreach (var data in EventList)
{
UserInfoList.Add(data);
}
return true;
}
protected override void OnPreExecute()
{
base.OnPreExecute();
}
protected override void OnPostExecute(Java.Lang.Object result)
{
base.OnPostExecute(result);
ListView.Adapter = new UserInfoListAdapter(context, UserInfoList);
}
}
class UserInfoListAdapter : BaseAdapter<UserInfo>
{
private List<UserInfo> mItem = new List<UserInfo>();
private Context context;
public UserInfoListAdapter(Context mcontext, List<UserInfo> mItems)
{
mItem.Clear();
mItem = mItems;
context = mcontext;
this.NotifyDataSetChanged();
}
public override UserInfo this[int position]
{
get
{
return mItem[position];
}
}
public override int Count
{
get
{
return mItem.Count;
}
}
public Context MContext { get; private set; }
public override long GetItemId(int position)
{
return position;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View listitem = convertView;
listitem = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.ListViewDesign, parent, false);
TextView TxtName = listitem.FindViewById<TextView>(Resource.Id.TxtName);
TextView TxtNumber = listitem.FindViewById<TextView>(Resource.Id.TxtNumber);
TxtName.Text = mItem[position].firstname;
TxtNumber.Text = mItem[position].contact_no;
listitem.Click += (object sender, EventArgs e) =>
{
Toast.MakeText(parent.Context, "Clicked " + mItem[position].firstname, ToastLength.Long).Show();
};
return listitem;
}
}
}
I want to put buttons in the ListView, one per row. Here is the example of how I want to implement it
Now when user click on button, a pdf file should download based on current id from database. For example in my database xray id is 1, so when user download pdf for xray it should download based on id which is 1
Place TableLayout in your 'ListViewDesign' android layout in order to
get required view (or it can be achieved by Linear Layout by setting
its orientation horizontal and its layout_weight)
Place Button in Fourth Column
Remove Click Event from GetView Method
Access Button in GetView Method
Button DownloadButton = view.FindViewbyId<Button>(Resource.Id.btn_download);
DownloadButton.Click += delegate { DownloadFile( link + mItem[position].Id ) };
Add Namespaces
using System.Net;
using System.IO;
using System.Text;
Add a new method in your listView Adapter Class
private void DownloadFile(string url)
{
var webClient = new WebClient();
webClient.DownloadStringCompleted += (s, e) => {
var text = e.Result; // get the downloaded text
string documentsPath = System.Environment.GetFolderPath(System.Environment.SpecialFolder.Personal);
string localFilename = "downloaded.txt";
string localPath = Path.Combine(documentsPath, localFilename);
File.WriteAllText(localPath, text); // writes to local storage
};
var url = new Uri("http://xamarin.com");
webClient.Encoding = Encoding.UTF8;
webClient.DownloadStringAsync(url);
RunOnUiThread(() => {
Toast.MakeText(this, "Download Completed", ToastLength.Short).Show();
});
}

How to validate a spinner in Xamarin Android

I'm trying to validate a spinner in C# in xamarin in visual studio if the user didn't select an option. similar to setError in TextView, I have seen examples in SO but all of them are for java if I'm not wrong.
This is my spinner
Spinner spinnerJobTypes = FindViewById<Spinner>(Resource.Id.spinnerJobTypes);
and this does not work for me
TextView errorText = (TextView)mySpinner.getSelectedView();
I would like to display this, if the user hasn't selected anything
else if (spinnerJobTypes.SelectedItem.ToString() == "-Select-")
{
//Display validation error
}
Any help is appreciated,
Spinner spinnerJobTypes = FindViewById<Spinner>(Resource.Id.spinnerJobTypes);
spinnerJobTypes.ItemSelected += new EventHandler<AdapterView.ItemSelectedEventArgs> (spinner_ItemSelected);
private void spinner_ItemSelected (object sender, AdapterView.ItemSelectedEventArgs e)
{
Spinner spinner = (Spinner)sender;
string toast = string.Format ("The planet is {0}", spinner.GetItemAtPosition (e.Position));
Toast.MakeText (this, toast, ToastLength.Long).Show ();
}
for reference https://developer.xamarin.com/guides/android/user_interface/spinner/
Edited:
Use this and check
errorText.SetCompoundDrawablesWithIntrinsicBounds(0, 0, Resource.Drawable.errorIcon, 0);
My Suggestion is, add an "None selected" view to the Spinner and use a bool parameter to identify whether user has selected certain item or not:
SpinnerAdapter.cs
public class SpinnerAdapter : BaseAdapter<String>
{
Context context;
List<String> list;
public SpinnerAdapter(Context c, List<String> list)
{
context = c;
this.list = list;
}
public override string this[int position] => list[position-1];
public override int Count => this.list.Count+1;
public override long GetItemId(int position)
{
return 0;
}
public override View GetView(int position, View convertView, ViewGroup parent)
{
View view;
if (position == 0)
{
view = LayoutInflater.From(context).Inflate(Resource.Layout.spinner_error,null);
var txtView = view.FindViewById<TextView>(Resource.Id.tvErr);
view.FindViewById<TextView>(Resource.Id.tvErr).Text = "None Selected";
//uncomment the following line if you want to show the error icon inside of spinner
//view.FindViewById<TextView>(Resource.Id.tvErr).Error = "";
}
else
{
view = convertView;
if (view == null|| view.FindViewById<TextView>(Resource.Id.tvItem)==null)
{
view = LayoutInflater.From(context).Inflate(Resource.Layout.spinner_item, null);
}
view.FindViewById<TextView>(Resource.Id.tvItem).Text = list[position-1];
}
return view;
}
}
MainActivity:
public class MainActivity : Activity
{
Spinner mSpinner;
bool validatePass=false;
TextView tvResult;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
mSpinner = FindViewById<Spinner>(Resource.Id.mSpinner);
var list = InitList();
SpinnerAdapter adapter = new SpinnerAdapter(this, list);
tvResult = FindViewById<TextView>(Resource.Id.tvResult);
mSpinner.Adapter = adapter;
mSpinner.ItemSelected += MSpinner_ItemSelected;
}
private void MSpinner_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
{
//use validatePass to indicate if user has selected something.
if (e.Position != 0)
{
validatePass = true;
}
else
{
validatePass = false;
}
tvResult.Text ="Validate Result: "+ validatePass.ToString();
}
private List<string> InitList()
{
List<string> list = new List<string>();
for (int i = 0; i < 15; i++)
{
list.Add("Item: " + i);
}
return list;
}
}
But if you really want to show the error icon inside the spinner, you can set the TextView.Error inside of GetView.
Here is my complete Demo:HelloSpinner.

Edit text in Listview Custom Adapter Loses its position while scrolling? - c# - Xamarin.Android

When we enter value in row 1 the value entered in row 1 is appearing back in row 6 when we scroll to the row 6. Please see the below code and advice.
namespace Kites
{
public class Marks
{
// add any if you need more
public string StudentName { get; set; }
public string MarksScored { get; set; }
}
public class TEXTCHECK
{
public int POS { get; set; }
public string Value { get; set; }
}
public class MarksListViewAdapter : BaseAdapter<Marks>
{
private List<Marks> mstuduentmarks;
private List<TEXTCHECK> abc = new List<TEXTCHECK>();
private Context mcontext;
public MarksListViewAdapter (Context context, List<Marks> stud)
{
mstuduentmarks = stud;
mcontext = context;
}
public override int Count
{
get
{
return mstuduentmarks.Count;
// return mattendence.Count;
}
}
public override long GetItemId (int position)
{
return position;
}
public override Marks this[int position]
{
get
{
return mstuduentmarks [position];
// return mattendence [position];
}
}
class ViewHolder : Java.Lang.Object
{
public EditText comsevin;
public TextView namenmn;
}
public override View GetView (int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
View view = convertView;
if (view == null) // otherwise create a new one
{
view = LayoutInflater.From(mcontext).Inflate(Resource.Layout.listview_Marks, null, false);
holder = new ViewHolder();
holder.comsevin = view.FindViewById<EditText>(Resource.Id.editTextTeacherMarks);
holder.namenmn = view.FindViewById<TextView>(Resource.Id.textStudentNameTeacherMarks);
holder.namenmn.Tag = position;
view.Tag = holder;
}
else
{
holder = (ViewHolder)view.Tag;
}
holder.namenmn.Text = mstuduentmarks[position].StudentName;
int pos = (int)holder.namenmn.Tag;
holder.comsevin.TextChanged += (sender, e) =>
{
abc[pos].Value = holder.comsevin.Text;
};
//TextView txtStudent =
//txtStudent.Text = mstuduentmarks[position].StudentName;
//txtMarks.FocusChange += (object sender, View.FocusChangeEventArgs e) =>
//{
// //txtMarks.RequestFocusFromTouch ();
// mstuduentmarks[position].MarksScored = txtMarks.Text;
//};
holder.comsevin.BeforeTextChanged += (sender, e) =>
{
abc.Add(new TEXTCHECK { POS = position, Value = mstuduentmarks[position].MarksScored });
};
holder.comsevin.AfterTextChanged += (sender, e) =>
{
int a = abc[pos].POS;
mstuduentmarks[pos].MarksScored = abc[pos].Value;
};
//txtMarks.Tag = position;
//txtMarks.TextChanged += TxtMarks_TextChanged;
return view;
}
//void TxtMarks_TextChanged (object sender, Android.Text.TextChangedEventArgs e)
//{
// EditText txtMarks = (EditText)sender;
// //var position = (int)txtMarks.Tag;
//}
}
}
When we enter value in row 1 the value entered in row 1 is appearing back in row 6 when we scroll to the row 6. Please see the below code and advice.
As a rule of thumb, when experiencing lists that don't reflect the dataset (experiencing item repetition for example) in listview / recyclerview it means that you're either using dirty views which were previously used and then uncorrectly Re-Bound, or simply using wrong positions during bind
I see where you are getting it wrong:
if (view == null) // otherwise create a new one
{
view = LayoutInflater.From(mcontext).Inflate(Resource.Layout.listview_Marks, null, false);
holder = new ViewHolder();
holder.comsevin = view.FindViewById<EditText>(Resource.Id.editTextTeacherMarks);
holder.namenmn = view.FindViewById<TextView>(Resource.Id.textStudentNameTeacherMarks);
holder.namenmn.Tag = position;//<------------here!!!
view.Tag = holder;
}
TLDR Don't save positions this way.
Whats happening: this instance of your view is being reused by listView, meaning that sometimes (many times) if (view == null) will be false and this means Tag property will not be updated for row 6 (or any other calls that will use recycled Views) and you are in fact using a dirty value.
You are then trying to use the Tag property as position, but forgetting this tag is already dirty if the view was recycled
int pos = (int)holder.namenmn.Tag;
holder.comsevin.TextChanged += (sender, e) =>
{
abc[pos].Value = holder.comsevin.Text;
};
Since you have access to the position in this method call you should use it directly
take a look at this guide from Java Code geeks even though it's in Java you will be able to see a good implementation of the old ViewHolder/ListView pattern.
Hope this helps

Disable click or touch for items in ListActivity Xamarin.Android

I have an Activity inherited from ListActivity. Inside I have a SimpleListItemChecked layout. I have an Ilist called codes. I have made items checked if they contain certain word which works fine. I now want to make the items not-editable/clickable.
public class ScanHistoryActivity : ListActivity
{
protected override void OnCreate(Bundle bundle)
{
var codes = Intent.Extras.GetStringArrayList("Codes");
base.OnCreate(bundle);
codes.ToList();
ListAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItemChecked, codes);
ListView lv = FindViewById<ListView>(Android.Resource.Id.List);
lv.ChoiceMode = ChoiceMode.Multiple;
foreach (var c in codes)
{
if (c.Contains("Success"))
{
int position = codes.IndexOf(c);
lv.SetItemChecked(position, true);
// Here i tried:
// lv.clickable = false; but didn't work
}
}
}
}
Tried this but not working unfortunatley..
protected override void OnCreate(Bundle bundle)
{
var codes = Intent.Extras.GetStringArrayList("Codes");
base.OnCreate(bundle);
codes.ToList();
ListAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItemChecked, codes);
ListView lv = FindViewById<ListView>(Android.Resource.Id.List);
lv.ChoiceMode = ChoiceMode.Multiple;
lv.Clickable = false;
lv.Focusable = false;
foreach (var c in codes)
{
long id = lv.GetItemIdAtPosition(codes.IndexOf(c));
if (c.Contains("Success"))
{
int position = codes.IndexOf(c);
lv.SetItemChecked(position, true);
OnListItemClick(lv,lv, position, id);
}
}
}
protected override void OnListItemClick(ListView l, View v, int position, long id)
{
l.Clickable = false;
l.Focusable = false;
}
Tried this as well: Made my own adapter to try get it working better:
protected override void OnCreate(Bundle bundle)
{
var codes = Intent.Extras.GetStringArrayList("Codes");
base.OnCreate(bundle);
codes.ToList();
ListAdapter = new ScanHistoryAdapter(this, codes.ToArray());
ListView lv = FindViewById<ListView>(Android.Resource.Id.List);
lv.ChoiceMode = ChoiceMode.Multiple;
lv.Clickable = false;
lv.Focusable = false;
foreach (var c in codes)
{
long id = lv.GetItemIdAtPosition(codes.IndexOf(c));
if (c.Contains("Success"))
{
int position = codes.IndexOf(c);
lv.SetItemChecked(position, true);
View v = FindViewById(ListAdapter.GetItemId();
OnListItemClick(lv,lv, position, id);
}
}
}
protected override void OnListItemClick(ListView l, View v, int position, long id)
{
l.Clickable = false;
l.Focusable = false;
}
simply We use to pass false value to setClickable method to disable clicking in java like this way.
ListView myList = (ListView) findViewById(R.id.list_view_id);
myList.setClickable(false);
Try once !!! There may be some methods like same...
We have some method to override and make specific item unclickable like this way
#Override
public boolean isEnabled(int position) {
if(position == your_item_pos) {
return false;
}
return true;
}

Categories

Resources