I got an issue with my Android program when updating user data on Fragment_profile. Fragment_Profile loads User profile data and contains an update button in which the button navigates to an activity called EditProfileActivity. Users can technically update the data but, after they save the updated data, the data still can't be updated. The old data still appear. I try to refresh the fragment by using OnResume() and add OnRestart on my EditProfileActivity.cs and OnPause both in fragment and activity but, still nothing. I am using Xamarin Android and develop it with C#. For more info, you can see what happened in the GIF
My issue
So far, I've tried to code, and here's my code.
Fragment_profile.cs
public class Fragment_Profile : Android.Support.V4.App.Fragment
{
public HomePageActivity m_currentActivity;
public TextView m_tv_loginname, m_tv_username, m_tv_fullname , m_tv_dob;
public Boolean isRefreshing = false;
public override void OnCreate(Bundle aSavedInstanceState)
{
base.OnCreate(aSavedInstanceState);
}
//public static Fragment_Profile NewInstance(Model.User aCurrentUser)
public static Fragment_Profile NewInstance()
{
var _frag4 = new Fragment_Profile { Arguments = new Bundle() };
return _frag4;
}
public override View OnCreateView(LayoutInflater aInflater, ViewGroup aContainer, Bundle aSavedInstanceState)
{
var _ignored = base.OnCreateView(aInflater, aContainer, aSavedInstanceState);
var view= aInflater.Inflate(Resource.Layout.FragmentProfile, null);
m_tv_loginname = view.FindViewById<TextView>(Resource.Id.tv_loginname);
m_tv_username = view.FindViewById<TextView>(Resource.Id.tv_userEmail);
m_tv_fullname = view.FindViewById<TextView>(Resource.Id.tv_fullname);
m_tv_dob = view.FindViewById<TextView>(Resource.Id.tv_dob);
Button _updateProfile = view.FindViewById<Button>(Resource.Id.btnUpdateProfile);
_updateProfile.Click += _updateProfile_Click;
m_currentActivity = (HomePageActivity)this.Activity;
if (m_currentActivity.CurrentUser != null)
{
//string = "Welcome, " + m_currentActivity.CurrentUser.UserName;
m_tv_loginname.Text = m_currentActivity.CurrentUser.LoginName;
m_tv_fullname.Text = m_currentActivity.CurrentUser.UserName;
m_tv_username.Text = m_currentActivity.CurrentUser.UserEmail;
m_tv_dob.Text = m_currentActivity.CurrentUser.DateOfBirth;
}
else
{
Toast.MakeText(Activity, "The data is not found!", ToastLength.Short).Show();
Intent i = new Intent(Context, typeof(MainActivity));
StartActivity(i);
this.Activity.Finish();
}
return view;
}
private void _updateProfile_Click(object sender, EventArgs e)
{
Intent i = new Intent(Context, typeof(EditProfileActivity));
i.PutExtra("loginname", m_currentActivity.CurrentUser.LoginName);
i.PutExtra("fullname", m_currentActivity.CurrentUser.UserName);
i.PutExtra("useremail", m_currentActivity.CurrentUser.UserEmail);
i.PutExtra("dob", m_currentActivity.CurrentUser.DateOfBirth);
StartActivity(i);
}
public override void OnResume()
{
base.OnResume();
if (isRefreshing)
{
Fragment fragment = new Fragment_Profile();
Android.Support.V4.App.FragmentManager fragmentMg = Activity.SupportFragmentManager;
FragmentTransaction fragmentTrans = fragmentMg.BeginTransaction();
fragmentTrans.Replace(Resource.Id.content_frame, fragment);
fragmentTrans.Detach(fragment);
fragmentTrans.Attach(fragment);
fragmentTrans.Commit();
//adapter.notifyDataSetChanged();
}
}
public override void OnPause()
{
base.OnPause();
isRefreshing = true;
}
}
When user click the _updateProfile button It will reference to next activity which is EditProfileActivity. Here's my EditProfileActivity.cs
public class EditProfileActivity : Activity, IOnDateSetListener
{
public EditText m_editFullName, m_editUsername, m_dob;
public TextView m_tvEmail;
public Button m_btnUpdate;
public Boolean isRefreshing = false;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.EditProfile);
m_editFullName = FindViewById<EditText>(Resource.Id.et_editfullName);
m_editUsername = FindViewById<EditText>(Resource.Id.et_editUserName);
m_tvEmail = FindViewById<TextView>(Resource.Id.tv_Email);
m_dob = FindViewById<EditText>(Resource.Id.et_editDob);
m_btnUpdate = FindViewById<Button>(Resource.Id.btn_updateprofile);
m_btnUpdate.Click += _btnUpdate_Click;
m_dob.Click += _dob_Click;
Bundle extras = Intent.Extras;
m_editFullName.Text = extras.GetString("loginname");
m_editUsername.Text = extras.GetString("fullname");
m_tvEmail.Text = extras.GetString("useremail");
m_dob.Text = extras.GetString("dob");
}
private void _btnUpdate_Click(object sender, EventArgs e)
{
try
{
Model.User _currentUser = Model.User.CheckEmailUser(m_tvEmail.Text);
_currentUser.UserName = m_editUsername.Text;
_currentUser.LoginName = m_editFullName.Text;
_currentUser.UserEmail = m_tvEmail.Text;
_currentUser.DateOfBirth = m_dob.Text;
var _updated = DBManager.Instance.Update(_currentUser);
if (_updated > 0)
{
Toast.MakeText(this, "Your account has been succesfully updated!", ToastLength.Long).Show();
Finish();
OnResume();
}
else
{
Toast.MakeText(this, "Failed to update!", ToastLength.Long).Show();
}
}
catch(Exception ex)
{
Toast.MakeText(this, ex.ToString(), ToastLength.Short).Show();
}
}
private void _dob_Click(object sender, EventArgs e)
{
var _dateTimeNow = DateTime.Now;
DatePickerDialog _datepicker = new DatePickerDialog(this, this
, _dateTimeNow.Year, _dateTimeNow.Month, _dateTimeNow.Day);
_datepicker.Show();
}
public void OnDateSet(DatePicker view, int year, int month, int dayOfMonth)
{
m_dob.Text = new DateTime(year, month + 1, dayOfMonth).ToShortDateString();
}
protected override void OnRestart()
{
base.OnRestart();
if (isRefreshing)
{
isRefreshing = false;
Finish();
}
}
protected override void OnPause()
{
base.OnPause();
if (!isRefreshing)
isRefreshing = true;
}
}
I also have read some articles that have the same problems as me but, It still confusing me and still same. I know it's a simple thing but, It took a few days for me because I am a newby and I still don't get the solution.
Do you guys have any ideas? Would you like to help me? If you don't mind please check my source code so, I know what I am missing. Thank in advance for your help!
In you Fragment, you can override the OnResume method. If you back to the fragment from Acitivty. you should query the new data from DB, then set the new value to the controls in Fragment.
public override void OnResume()
{
base.OnResume();
PHName.Text = photoDAO.GetFirstPhotos(Id).PhotoName;
}
Here is running GIF.
You can see this lifecycle about Fragment. Every time you display the Fragment,OnResume method will be executed. You get the newest data from DB, then set it to the Fragment page.
Here is my demo.
https://drive.google.com/file/d/11dROKS7TtqAaVYkG8w6ZKpqnQJRBD87E/view
Related
I am developing an inventory management app in xamarin forms using Zebra TC20 model. Right now I am able to retrieve barcode data using datawedge. Now I am trying to disable and enable barcode scanner using datawedge as well. I have surfed and found out we can broadcast to datawedge for enable and disable the barcode scanner. Now I am having the issue when I want to enable or disable the the scanner from a page I am retrieving an error message Java.Lang.NullPointerException: 'Attempt to invoke virtual method 'void android.content.Context.sendBroadcast(android.content.Intent)' on a null object reference . The scanner functions are implemented in Android file. I am using dependency service to call the scanner functions. I have attached the code I have done.
MainActivity.cs
public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity, IKeyboardListener, IScannerConnection
{
private static string ACTION_DATAWEDGE_FROM_6_2 = "com.symbol.datawedge.api.ACTION";
private static string EXTRA_CREATE_PROFILE = "com.symbol.datawedge.api.CREATE_PROFILE";
private static string EXTRA_SET_CONFIG = "com.symbol.datawedge.api.SET_CONFIG";
private static string EXTRA_PROFILE_NAME = "Barcode Scan";
private DataWedgeReceiver _broadcastReceiver = null;
protected override void OnCreate(Bundle bundle)
{
base.Window.RequestFeature(WindowFeatures.ActionBar);
// Name of the MainActivity theme you had there before.
// Or you can use global::Android.Resource.Style.ThemeHoloLight
base.SetTheme(Resource.Style.MainTheme);
TabLayoutResource = Resource.Layout.Tabbar;
ToolbarResource = Resource.Layout.Toolbar;
base.OnCreate(bundle);
DependencyService.Register<ToastNotification>(); // Register your dependency
ToastNotification.Init(this);
var container = new SimpleContainer(); // Create a SimpleCOntainer
container.Register<IGeolocator, Geolocator>(); // Register the Geolocator
container.Register<IDevice>(t => AndroidDevice.CurrentDevice); // Register the Device
Resolver.ResetResolver(); // Reset the resolver
Resolver.SetResolver(container.GetResolver()); // Resolve it
FFImageLoading.Forms.Platform.CachedImageRenderer.Init(enableFastRenderer: true);
UserDialogs.Init(this);
Rg.Plugins.Popup.Popup.Init(this, bundle);
global::Xamarin.Forms.Forms.Init(this, bundle);
global::ZXing.Net.Mobile.Forms.Android.Platform.Init();
_broadcastReceiver = new DataWedgeReceiver();
App inventoryApp = new App(OnSaveSignature);
_broadcastReceiver.scanDataReceived += (s, scanData) =>
{
MessagingCenter.Send<App, string>(inventoryApp, "ScanBarcode", scanData);
};
CreateProfile();
//DependencyService.Register<ToastNotification>();
//ToastNotification.Init(this, new PlatformOptions() { SmallIconDrawable = Android.Resource.Drawable.IcDialogInfo });
LoadApplication(inventoryApp);
}
public override void OnBackPressed()
{
if (Rg.Plugins.Popup.Popup.SendBackPressed(base.OnBackPressed))
{
// Do something if there are some pages in the `PopupStack`
}
else
{
// Do something if there are not any pages in the `PopupStack`
}
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
// check if the current item id
// is equals to the back button id
if (item.ItemId == 16908332 && !RFIDStockCountViewModel.IsPosted && RFIDStockCountViewModel.IsStockCounting)
{
return false;
/*
if (Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack.Count > 0)
{
//LIFO is the only game in town! - so send back the last page
int index = Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack.Count - 1;
var currPage = (CustomContentPage)Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack[index];
// check if the page has subscribed to
// the custom back button event
if (currPage?.CustomBackButtonAction != null)
{
// invoke the Custom back button action
currPage?.CustomBackButtonAction.Invoke();
// and disable the default back button action
return false;
}
}
// if its not subscribed then go ahead
// with the default back button action
return base.OnOptionsItemSelected(item);
*/
}
else
{
// since its not the back button
//click, pass the event to the base
return base.OnOptionsItemSelected(item);
}
}
private async Task<bool> OnSaveSignature(Stream bitmap, string filename)
{
var path = Android.OS.Environment.GetExternalStoragePublicDirectory(Android.OS.Environment.DirectoryPictures).AbsolutePath;
var file = Path.Combine(path, "signature.png");
using (var dest = File.OpenWrite(file))
{
await bitmap.CopyToAsync(dest);
}
return true;
}
//public override void OnBackPressed()
//{
// if (Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack.Count > 0)
// {
// //LIFO is the only game in town! - so send back the last page
// int index = Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack.Count - 1;
// var currentpage = (CustomContentPage)Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack[index];
// // check if the page has subscribed to
// // the custom back button event
// if (currentpage?.CustomBackButtonAction != null)
// {
// currentpage?.CustomBackButtonAction.Invoke();
// }
// else
// {
// base.OnBackPressed();
// }
// }
//}
public override bool OnKeyDown(Keycode keyCode, KeyEvent e)
{
if (e.KeyCode.GetHashCode() == 139 || e.KeyCode.GetHashCode() == 280)
{
MessagingCenter.Send<IKeyboardListener, string>(this, "KeyboardListener", "TRUE");
}
return base.OnKeyDown(keyCode, e);
}
public override bool OnKeyUp(Keycode keyCode, KeyEvent e)
{
if (e.KeyCode.GetHashCode() == 139 || e.KeyCode.GetHashCode() == 280)
{
MessagingCenter.Send<IKeyboardListener, string>(this, "KeyboardListener", "FALSE");
}
return base.OnKeyDown(keyCode, e);
}
protected override void OnResume()
{
base.OnResume();
if (null != _broadcastReceiver)
{
// Register the broadcast receiver
IntentFilter filter = new IntentFilter(DataWedgeReceiver.IntentAction);
filter.AddCategory(DataWedgeReceiver.IntentCategory);
Android.App.Application.Context.RegisterReceiver(_broadcastReceiver, filter);
}
}
protected override void OnPause()
{
if (null != _broadcastReceiver)
{
// Unregister the broadcast receiver
Android.App.Application.Context.UnregisterReceiver(_broadcastReceiver);
}
base.OnStop();
}
private void CreateProfile()
{
String profileName = EXTRA_PROFILE_NAME;
SendDataWedgeIntentWithExtra(ACTION_DATAWEDGE_FROM_6_2, EXTRA_CREATE_PROFILE, profileName);
// Now configure that created profile to apply to our application
Bundle profileConfig = new Bundle();
profileConfig.PutString("PROFILE_NAME", EXTRA_PROFILE_NAME);
profileConfig.PutString("PROFILE_ENABLED", "true"); // Seems these are all strings
profileConfig.PutString("CONFIG_MODE", "CREATE_IF_NOT_EXIST");
Bundle barcodeConfig = new Bundle();
barcodeConfig.PutString("PLUGIN_NAME", "BARCODE");
//barcodeConfig.PutString("RESET_CONFIG", "true"); // This is the default but never hurts to specify
Bundle barcodeProps = new Bundle();
barcodeProps.PutString("scanner_input_enabled", "true"); // This is the default but never hurts to specify
barcodeProps.PutString("scanner_selection_by_identifier", "AUTO ");
barcodeProps.PutString("scanner_selection", "auto ");
barcodeProps.PutString("aim_mode", "off ");
barcodeProps.PutString("illumination_mode", "off ");
barcodeConfig.PutBundle("PARAM_LIST", barcodeProps);
profileConfig.PutBundle("PLUGIN_CONFIG", barcodeConfig);
Bundle appConfig = new Bundle();
appConfig.PutString("PACKAGE_NAME", this.PackageName); // Associate the profile with this app
appConfig.PutStringArray("ACTIVITY_LIST", new String[] { "*" });
profileConfig.PutParcelableArray("APP_LIST", new Bundle[] { appConfig });
SendDataWedgeIntentWithExtra(ACTION_DATAWEDGE_FROM_6_2, EXTRA_SET_CONFIG, profileConfig);
// You can only configure one plugin at a time, we have done the barcode input, now do the intent output
profileConfig.Remove("PLUGIN_CONFIG");
Bundle intentConfig = new Bundle();
intentConfig.PutString("PLUGIN_NAME", "INTENT");
intentConfig.PutString("RESET_CONFIG", "true");
Bundle intentProps = new Bundle();
intentProps.PutString("intent_output_enabled", "true");
intentProps.PutString("intent_action", DataWedgeReceiver.IntentAction);
intentProps.PutString("intent_delivery", "2");
intentConfig.PutBundle("PARAM_LIST", intentProps);
profileConfig.PutBundle("PLUGIN_CONFIG", intentConfig);
SendDataWedgeIntentWithExtra(ACTION_DATAWEDGE_FROM_6_2, EXTRA_SET_CONFIG, profileConfig);
}
private void SendDataWedgeIntentWithExtra(String action, String extraKey, Bundle extras)
{
Intent dwIntent = new Intent();
dwIntent.SetAction(action);
dwIntent.PutExtra(extraKey, extras);
SendBroadcast(dwIntent);
}
private void SendDataWedgeIntentWithExtra(String action, String extraKey, String extraValue)
{
Intent dwIntent = new Intent();
dwIntent.SetAction(action);
dwIntent.PutExtra(extraKey, extraValue);
SendBroadcast(dwIntent);
}
public void SendScannerEnable()
{
SendDataWedgeIntentWithExtra(ACTION_DATAWEDGE_FROM_6_2, EXTRA_SET_CONFIG, "ENABLE_PLUGIN");
}
public void SendScannerDisable()
{
SendDataWedgeIntentWithExtra(ACTION_DATAWEDGE_FROM_6_2, EXTRA_SET_CONFIG, "DISABLE_PLUGIN");
}
}
}
Snip from Page.cs
protected override void OnAppearing()
{
DependencyService.Get<IScannerConnection>().SendScannerEnable();
MessagingCenter.Subscribe<App, string>(this, "ScanBarcode", (sender, arg) =>
{
ScanBarcode(arg);
});
base.OnAppearing();
}
I have searched through internet but I didn't get any resource on how to fix it.
Thank you.
The url below helped me to fix my problem. I had to create a new scanner class which enables and disables datawedge profile by triggering events. https://developer.zebra.com/community/home/blog/2018/07/11/xamarinforms-freshmvvm-datawedge-take-2
I am building a Xamarin.Android application for a Zebra TC-70 Android device. My main activity runs the scanner just fine the first time through. It gets the data from the scanner and then passes data to another activity just fine. If I cancel the new activity or complete my work and return to the first activity, the scanner does not re-initialize. Here is my code:
[Activity(Label = "MyApp", MainLauncher = true, Icon = "#mipmap/icon",
ScreenOrientation = ScreenOrientation.Portrait)]
public class MainActivity : AppCompatActivity, EMDKManager.IEMDKListener
{
//EMDK
private BarcodeManager _barcodeManager;
private EMDKManager _emdkManager;
private EditText _scanBarcodeEditText;
private Scanner _scanner;
void EMDKManager.IEMDKListener.OnClosed()
{
if(_emdkManager != null)
{
_emdkManager.Release();
_emdkManager = null;
}
}
void EMDKManager.IEMDKListener.OnOpened(EMDKManager p0)
{
_emdkManager = p0;
InitScanner();
}
protected override void OnResume()
{
base.OnResume();
var intent = new Intent(this, typeof(FpmsDataService));
BindService(intent, _dataServiceConnection, Bind.AutoCreate);
_scanBarcodeEditText.Text = string.Empty;
InitScanner();
}
protected override void OnPause()
{
base.OnPause();
UnbindService(_dataServiceConnection);
DeinitScanner();
if (_emdkManager != null)
{
_emdkManager.Release();
_emdkManager = null;
}
}
protected override void OnDestroy()
{
base.OnDestroy();
DeinitScanner();
if(_emdkManager != null)
{
_emdkManager.Release();
_emdkManager = null;
}
Log.Information("Destroyed FirePMS MainActivity");
Log.CloseAndFlush();
}
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
Window.SetFlags(WindowManagerFlags.KeepScreenOn, WindowManagerFlags.KeepScreenOn);
SetContentView(Resource.Layout.Main);
_scanBarcodeEditText = FindViewById<EditText>(Resource.Id.MaintenanceScanBarcode_EditText);
//Initialize Scanner
var results = EMDKManager.GetEMDKManager(Application.Context, this);
}
private void InitScanner()
{
if(_emdkManager != null)
{
if(_barcodeManager == null)
{
try
{
//Get the feature object such as BarcodeManager object for accessing the feature.
_barcodeManager = (BarcodeManager)_emdkManager.GetInstance(EMDKManager.FEATURE_TYPE.Barcode);
_scanner = _barcodeManager.GetDevice(BarcodeManager.DeviceIdentifier.Default);
if (_scanner != null)
{
//Attach the Data Event handler to get the data callbacks.
_scanner.Data += Scanner_Data;
_scanner.Status += Scanner_Status;
_scanner.Enable();
}
else
{
Log.Error("Failed to enable scanner");
}
}
catch (ScannerException e)
{
Log.Error(e.Message);
}
catch (Exception ex)
{
Log.Error(ex.Message);
}
}
}
}
private void Scanner_Status(object sender, Scanner.StatusEventArgs e)
{
var state = e.P0.State;
if(state == StatusData.ScannerStates.Idle)
{
try
{
if (_scanner.IsEnabled &&
!_scanner.IsReadPending)
{
SetScannerConfig();
_scanner.Read();
}
}
catch (ScannerException e1)
{
Log.Error(e1.Message);
}
}
}
private void DeinitScanner()
{
if(_emdkManager != null)
{
if(_scanner != null)
{
try
{
_scanner.CancelRead();
_scanner.Disable();
_scanner.Data -= Scanner_Data;
_scanner.Status -= Scanner_Status;
_scanner.Release();
}
catch (ScannerException e)
{
Log.Error(e.Result.Description);
}
}
}
if (_barcodeManager != null)
{
_emdkManager.Release(EMDKManager.FEATURE_TYPE.Barcode);
}
_barcodeManager = null;
_scanner = null;
}
private void SetScannerConfig()
{
var config = _scanner.GetConfig();
config.SkipOnUnsupported = ScannerConfig.SkipOnUnSupported.None;
config.ScanParams.DecodeLEDFeedback = true;
config.ReaderParams.ReaderSpecific.ImagerSpecific.PicklistEx = ScannerConfig.PicklistEx.Hardware;
config.DecoderParams.Code39.Enabled = true;
config.DecoderParams.Code128.Enabled = false;
_scanner.SetConfig(config);
}
private void Scanner_Data(object sender, Scanner.DataEventArgs e)
{
var scanDataCollection = e.P0;
if((scanDataCollection != null) && (scanDataCollection.Result == ScannerResults.Success))
{
var scanData = scanDataCollection.GetScanData();
if (scanData[0].Data == null)
{
return;
}
RunOnUiThread(() => _scanBarcodeEditText.Text = scanData[0].Data);
RunOnUiThread(ProcessScan);
}
}
private void ProcessScan()
{
if (string.IsNullOrEmpty(_scanBarcodeEditText.Text))
{
Toast.MakeText(this, "You must scan or enter a barcode to begin", ToastLength.Long).Show();
return;
}
else
{
var intent = new Intent(this, typeof(SecondActivity));
intent.PutExtra("ScannedData",_scanBarcodeEditText.Text);
StartActivity(intent)
}
}
}
Any suggestions would be greatly appreciated. As I indicated, the process works just fine the first time, it's when I return to this activity that the scanner is no longer initialized and doesn't come back.
I suspect the EMDK is not being properly released before the activity is restarted. If you take a look at the following article, though using Java the principle is the same and the advice there is to release the EMDK in onStop(). See the note about managing the EMDK instance about half way down.
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();
});
}
I have a 3 fragments on my view pager. On my 3rd fragment is a recyclerViewer which contains contact list. Now, i am finding it difficult as to how to update my contact list (recycleViewer with data) from my database. recycleview in Fragment.axml is inflated from Fragment 3.cs.
Fragment 3.cs
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
RecyclerView recyclerView = inflater.Inflate(Resource.Layout.Fragment3, container, false) as RecyclerView;
implementRecyclerView(recyclerView);
return recyclerView;
}
private void SetUpRecyclerView(RecyclerView recyclerView)
{
recyclerView.SetLayoutManager(new LinearLayoutManager(recyclerView.Context));
recyclerView.SetAdapter(Adapter);
recyclerView.Click += eventClicked;
Adapter.NotifyDataSetChanged();
recyclerView.SetItemClickListener((rv, position, view) =>
{
//An item has been clicked
Context context = view.Context;
Intent intent = new Intent(context, typeof(EventDetailActivity));
context.StartActivity(intent);
});
}
This is where my RecycleView that actually displays the contact list after being inflated in the Fragment 3.cs
Fragment 3 axml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
//id of RecycleView
android:id="#+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
In this activity, I add some data to my database. After adding, i call the RefreshListWithNewData() to update my RecyclerView (contact list). I keep getting NullReference trying to get the id of the RecycleView.
SomeActivity.cs
JavaList<Contact> myContactList = new JavaList<Contact>();
private async void AddNewGames(){
//add contacts to database
await RefreshListWithNewData()
}
private async Task RefreshListWithNewData(){
foreach(var item in items){
Contact people = new Contact();
people.Name = item.Object.Name;
myContactList.Add(people);
}
//trying to update recycleview in Fragment 3.cs
refreshRecycler = (RecyclerView)FindViewById(Resource.Id.recycleview)
adapter = new ContactAdapter(myContactList);
refreshRecycler.SetAdapter(adapter);
My question is why can't i reach that RecycleView even after i have given it an id called recycleview?
Updated Fragment3.cs
public class Fragment3 : SupportFragment
{
public RecyclerView refresh;
public override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
RecyclerView recyclerView = inflater.Inflate(Resource.Layout.Fragment3, container, false) as RecyclerView;
SetUpRecyclerView(recyclerView);
return recyclerView;
}
private void SetUpRecyclerView(RecyclerView recyclerView)
{
//var value= GetRandomSubList(PeaceEventsCollection.GetPeaceEvents(), 5);
var value = PeaceEventsCollection.GetPeaceEvents();
recyclerView.SetLayoutManager(new LinearLayoutManager(recyclerView.Context));
var Adapter = new EventAdapter(PeaceEventsCollection.GetPeaceEvents());
recyclerView.SetAdapter(Adapter);
recyclerView.Click += eventClicked;
Adapter.NotifyDataSetChanged();
recyclerView.SetItemClickListener((rv, position, view) =>
{
//An item has been clicked
Context context = view.Context;
Intent intent = new Intent(context, typeof(EventDetailActivity));
intent.PutExtra(EventDetailActivity.EXTRA_NAME, value[position].EName);
intent.PutExtra(EventDetailActivity.EXTRA_DETAIL, value[position].EDescritption);
intent.PutExtra(EventDetailActivity.EXTRA_DATE, value[position].EDate);
//perform activity to event page
context.StartActivity(intent);
});
}
private JavaList<PeaceEvents> GetRandomSubList(JavaList<PeaceEvents> items, int amount)
{
JavaList<PeaceEvents> list = new JavaList<PeaceEvents>();
Random random = new Random();
while (list.Count < amount)
{
list.Add(items[random.Next(items.Count)]);
}
return list;
}
private void eventClicked(object sender, EventArgs e)
{
Intent showEvent = new Intent(Context, typeof(EventActivity));
this.StartActivity(showEvent);
}
public class EventAdapter : RecyclerView.Adapter
{
private JavaList<PeaceEvents> peaceEvents;
public EventAdapter(JavaList<PeaceEvents> peaceEvents)
{
this.peaceEvents = peaceEvents;
}
public override void OnBindViewHolder(RecyclerView.ViewHolder holder, int position)
{
EventHolder hold = holder as EventHolder;
hold.EventName.Text = peaceEvents[position].EName;
hold.EventImg.SetImageResource(peaceEvents[position].EImage);
hold.EventDate.Text = peaceEvents[position].EDate;
hold.EventVenue.Text = peaceEvents[position].EVenue;
hold.EventDescription.Text = peaceEvents[position].EDescritption;
}
public override RecyclerView.ViewHolder OnCreateViewHolder(ViewGroup parent, int viewType)
{
View v = LayoutInflater.From(parent.Context).Inflate(Resource.Layout.List_Event, parent, false);
EventHolder holder = new EventHolder(v);
return holder;
}
public override int ItemCount
{
get { return peaceEvents.Size(); }
}
}
}
public class EventHolder : RecyclerView.ViewHolder
{
public TextView EventName;
public ImageView EventImg;
public TextView EventDate;
public TextView EventVenue;
public TextView EventDescription;
public TextView textIcon;
public TextView EventDetailDescription;
public EventHolder(View itemView) : base(itemView)
{
EventName = itemView.FindViewById<TextView>(Resource.Id.textViewEvent);
EventImg = itemView.FindViewById<ImageView>(Resource.Id.imageView);
EventDate = itemView.FindViewById<TextView>(Resource.Id.textViewDate);
EventVenue = itemView.FindViewById<TextView>(Resource.Id.textViewVenue);
EventDescription = itemView.FindViewById<TextView>(Resource.Id.textViewDescription);
}
}
EventActivity
public class EventActivity : AppCompatActivity
{
private EditText EventName;
private EditText EventDateTime;
private EditText EventVenue;
private EditText EventDescription;
private ProgressBar circular_progress;
private Button saveData;
private LinearLayout list_view;
private RecyclerView recycle;
// private EventAdapter adapter;
JavaList<PeaceEvents> peace_Events = new JavaList<PeaceEvents>();
// private PeaceEvents selectedEvents;
private const string FirebaseUrl = "";
private DrawerLayout mDrawerLayout;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
SetContentView(Resource.Layout.Events);
// Create your application here
SupportToolbar toolBar = FindViewById<SupportToolbar>(Resource.Id.toolBar);
SetSupportActionBar(toolBar);
//view
circular_progress = FindViewById<ProgressBar>(Resource.Id.circularProgress);
EventName = FindViewById<EditText>(Resource.Id.eventName);
EventDateTime = FindViewById<EditText>(Resource.Id.txtDateAndTime);
EventVenue = FindViewById<EditText>(Resource.Id.venue);
EventDescription = FindViewById<EditText>(Resource.Id.txtDescribe);
list_view = FindViewById<LinearLayout>(Resource.Id.list_view);
saveData = FindViewById<Button>(Resource.Id.btnLogin);
saveData.Click += saveEventData;
SupportActionBar ab = SupportActionBar;
ab.SetHomeAsUpIndicator(Resource.Drawable.ic_menu);
ab.SetDisplayHomeAsUpEnabled(true);
mDrawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawer_layout);
NavigationView navigationView = FindViewById<NavigationView>(Resource.Id.nav_view);
if (navigationView != null)
{
SetUpDrawerContent(navigationView);
}
}
private void saveEventData(object sender, EventArgs e)
{
CreateEvent();
}
private async void CreateEvent()
{
PeaceEvents events = new PeaceEvents();
events.EName = EventName.Text;
events.EDate = EventDateTime.Text;
events.EVenue = EventVenue.Text;
events.EDescritption = EventDescription.Text;
var firebase = new FirebaseClient(FirebaseUrl);
//add item
var item = await firebase.Child("").PostAsync<PeaceEvents>(events);
await LoadData();
}
private async Task LoadData()
{
circular_progress.Visibility = ViewStates.Visible;
var firebase = new FirebaseClient(FirebaseUrl);
var items = await firebase.Child("").OnceAsync<PeaceEvents>();
peace_Events.Clear();
EventAdapter adpater;
foreach(var item in items){
PeaceEvents events = new PeaceEvents();
events.EName = item.Object.EName;
events.EDate = item.Object.EDate;
events.EDescritption = item.Object.EDescritption;
events.EVenue = item.Object.EVenue;
events.EImage = item.Object.EImage;
peace_Events.Add(events);
}
// Fragment3.UpdateContactList<Ja>(peace_Events);
//adpater = new EventAdapter(peace_Events);
////recycle.SetAdapter(adpater);
////recycle.SetLayoutManager(new LinearLayoutManager(this));
//adpater.NotifyDataSetChanged();
//recycle.SetAdapter(adpater);
circular_progress.Visibility = ViewStates.Invisible;
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
case Android.Resource.Id.Home:
mDrawerLayout.OpenDrawer((int)GravityFlags.Left);
return true;
default:
return base.OnOptionsItemSelected(item);
}
}
private void SetUpDrawerContent(NavigationView navigationView)
{
navigationView.NavigationItemSelected += (object sender, NavigationView.NavigationItemSelectedEventArgs e) =>
{
int id = e.MenuItem.ItemId;
switch (id)
{
case Resource.Id.nav_home:
Intent home = new Intent(this, typeof(MainActivity));
this.StartActivity(home);
GC.Collect();
break;
case Resource.Id.nav_peacehero:
Intent intent = new Intent(this, typeof(PeaceFragement));
this.StartActivity(intent);
GC.Collect();
break;
//case Resource.Id.nav_discussion:
// Intent discuss = new Intent(this, typeof(PeaceHeroActivity));
// this.StartActivity(discuss);
// break;
//case Resource.Id.nav_event:
// Intent peace_event = new Intent(this, typeof(PeaceHeroActivity));
// this.StartActivity(peace_event);
// break;
//case Resource.Id.nav_donate:
//Intent donate = new Intent(this, typeof(PeaceHeroActivity));
//this.StartActivity(donate);
//break;
}
e.MenuItem.SetChecked(true);
mDrawerLayout.CloseDrawers();
};
}
}
}
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.