Dynamic population of dropdown based on another dropdown in xamarin android - xamarin

I am in need of getting state and corresponding cities from selected country, in Xamarin.Android (need not in Xamarin.Forms)
I populate the countries in Spinner control as shown below
Spinner spinnerMailingCountry;
int[] countryId = new int[] { 0, 58, 98, 105, 86 };
String[] countryName = { "Select", "England", "Germany", "India"};
ArrayAdapter<String> countryAdapter;
String countryIdByPosition;
int selectedPosition;
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
...
spinnerMailingCountry = FindViewById<Spinner>(Resource.Id.spinnerMailingCountry);
SetupCountrySpinner();
}
void SetupCountrySpinner()
{
countryAdapter = new ArrayAdapter<string>(this, Resource.Layout.spinner_item, countryName);
countryAdapter.SetDropDownViewResource(Resource.Layout.spinner_item);
spinnerMailingCountry.Adapter = countryAdapter;
spinnerMailingCountry.ItemSelected += new EventHandler<AdapterView.ItemSelectedEventArgs>(CountrySpinner_ItemSelected);
}
private void CountrySpinner_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
{
var spinner = (Spinner)sender;
selectedPosition = spinner.SelectedItemPosition;
countryIdByPosition = countryId[selectedPosition].ToString();
}
Now once a country is selected, I need to populate list of corresponding state in spinner. This flow is also for city too. How can I achieve this?
NOTE: State and city lists are getting from my database through API call.

Now once a country is selected, I need to populate list of corresponding state in spinner. This flow is also for city too. How can I achieve this?
When CountrySpinner_ItemSelected be invoked, you can set ArrayAdapter for State.And when State be selected, you can set ArrayAdapter for City.
axml:
<Spinner
android:id="#+id/spinnerCountry"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:spinnerMode="dialog" />
<Spinner
android:id="#+id/spinnerState"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:spinnerMode="dialog" />
<Spinner
android:id="#+id/spinnerCity"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:spinnerMode="dialog" />
Activity.cs : Adding test data( *stateName / cityName *)
Spinner spinnerMailingCountry;
Spinner spinnerMailingState;
Spinner spinnerMailingCity;
int[] countryId = new int[] { 0, 58, 98, 105, 86 };
String[] countryName = { "Select", "England", "Germany", "India" };
String[] stateName = { "Select", "EnglandStateOne", "EnglandStateTwo", "EnglandStateThree" };
String[] cityName = { "Select", "EnglandCityOne", "EnglandCityTwo", "EnglandCityThree" };
ArrayAdapter<String> countryAdapter;
ArrayAdapter<String> stateAdapter;
ArrayAdapter<String> cityAdapter;
String countryIdByPosition;
int selectedPosition;
OnCreate Method:
spinnerMailingCountry = FindViewById<Spinner>(Resource.Id.spinnerCountry);
spinnerMailingState = FindViewById<Spinner>(Resource.Id.spinnerState);
spinnerMailingState.Enabled = false;
spinnerMailingCity = FindViewById<Spinner>(Resource.Id.spinnerCity);
spinnerMailingCity.Enabled = false;
countryAdapter = new ArrayAdapter<string>(this, Resource.Layout.support_simple_spinner_dropdown_item, countryName);
spinnerMailingCountry.Adapter = countryAdapter;
spinnerMailingCountry.ItemSelected += new EventHandler<AdapterView.ItemSelectedEventArgs>(CountrySpinner_ItemSelected);
spinnerMailingState.ItemSelected += new EventHandler<AdapterView.ItemSelectedEventArgs>(StateSpinner_ItemSelected);
spinnerMailingCity.ItemSelected += new EventHandler<AdapterView.ItemSelectedEventArgs>(CitySpinner_ItemSelected);
CountrySpinner_ItemSelected : Display state according to country.
private void CountrySpinner_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
{
var spinner = (Spinner)sender;
selectedPosition = spinner.SelectedItemPosition;
countryIdByPosition = countryId[selectedPosition].ToString();
if(selectedPosition != 0) {
stateAdapter = new ArrayAdapter<string>(this, Resource.Layout.support_simple_spinner_dropdown_item, stateName);
//stateAdapter's data can get from your databse API with countryIdByPosition
spinnerMailingState.Enabled = true;
spinnerMailingState.Adapter = stateAdapter;
}
else
{
spinnerMailingState.Enabled = false;
}
}
StateSpinner_ItemSelected: Display city according to state.
private void StateSpinner_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
{
var spinner = (Spinner)sender;
selectedPosition = spinner.SelectedItemPosition;
cityAdapter = new ArrayAdapter<string>(this, Resource.Layout.support_simple_spinner_dropdown_item, cityName);
if (selectedPosition != 0)
{
spinnerMailingCity.Enabled = true;
spinnerMailingCity.Adapter = cityAdapter;
//cityAdapter' data can get from your databse API with selectedPosition
Console.WriteLine("-------------" + stateName[selectedPosition].ToString());
}
else
{
spinnerMailingCity.Enabled = false;
}
}
CitySpinner_ItemSelected: Show the city you want.
private void CitySpinner_ItemSelected(object sender, AdapterView.ItemSelectedEventArgs e)
{
var spinner = (Spinner)sender;
selectedPosition = spinner.SelectedItemPosition;
Console.WriteLine("-------------" + cityName[selectedPosition].ToString());
}
When OnDestroy , unregister ItemSelected event:
protected override void OnDestroy()
{
base.OnDestroy();
spinnerMailingCountry.ItemSelected -= new EventHandler<AdapterView.ItemSelectedEventArgs>(CountrySpinner_ItemSelected);
spinnerMailingState.ItemSelected -= new EventHandler<AdapterView.ItemSelectedEventArgs>(StateSpinner_ItemSelected);
spinnerMailingCity.ItemSelected -= new EventHandler<AdapterView.ItemSelectedEventArgs>(CitySpinner_ItemSelected);
}

Related

xamarin binding variable to label using timer event

I want to binding a variable to a label which as a children in a grid.
the variable changed with a timer event.pls check my code help me found out where i am wrong.I can see the label init value is 0,but it won't update when the variable do.
public class DevicePage : ContentPage
{
IDevice device;
Label testLb = new Label();
System.Timers.Timer testtimer;
Grid gridView;
byte testt { get; set; } = 0;
GetSendData communicate;
private byte _maintext;
public byte MainText
{
get
{
return _maintext;
}
set
{
_maintext = value;
OnPropertyChanged();
}
}
public DevicePage(IDevice currDevice)
{
device = currDevice;
this.Title = "Status";
testtimer = new System.Timers.Timer();
testtimer.Interval = 1000;
testtimer.Elapsed += OnTimedEvent;
testtimer.Enabled = true;
gridView = new Grid();
testLb.Text = testt.ToString();
testLb.SetBinding(Label.TextProperty, ".");
testLb.BindingContext = MainText;
gridView.Children.Add(testLb, 0, 0);
this.Content = gridView;
}
private void OnTimedEvent(object sender, System.Timers.ElapsedEventArgs e)
{
MainText += 1;
}
after I implement INotifyPropertyChanged,testLb won't update either.But I change testLb.SetBinding(Label.TextProperty, "."); testLb.BindingContext = MainText; to testLb.SetBinding(Label.TextProperty, "MainText"); testLb.BindingContext = this; It works!

Activity Indicator not working in Xamarin.Forms

I have an activity indicator designed inside a absolute layout. Based on a button click event, I try to show and hide the activity indicator alternatively. But due to some reason, I cannot see my activity Indicator.Any help will be greatly appreciated!!! Thanks in advance.
This is my .xaml.cs class:
public partial class PBTestPage : ContentPage
{
private bool _pbIndicator;
public PBTestPage()
{
InitializeComponent();
}
public bool PBIndicator{
get{
return _pbIndicator;
}set{
_pbIndicator = value;
OnPropertyChanged();
}
}
protected override void OnAppearing()
{
base.OnAppearing();
var parentLayout = new AbsoluteLayout();
var stackContent = new StackLayout();
AbsoluteLayout.SetLayoutFlags(stackContent,AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(stackContent,new Rectangle(0f,0f,AbsoluteLayout.AutoSize,AbsoluteLayout.AutoSize));
var activityIndicator = new ActivityIndicator
{
Color = Color.Black,
IsRunning = PBIndicator,
IsVisible = PBIndicator
};
AbsoluteLayout.SetLayoutFlags(activityIndicator, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(activityIndicator, new Rectangle(.5, .5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
var button = new Button
{
Text="Click",
VerticalOptions=LayoutOptions.CenterAndExpand,
HorizontalOptions=LayoutOptions.CenterAndExpand,
};
button.Clicked += OnClicked;
stackContent.Children.Add(button);
parentLayout.Children.Add(stackContent);
parentLayout.Children.Add(activityIndicator);
Content = parentLayout;
}
private void OnClicked(object sender, EventArgs e)
{
if(PBIndicator==false){
PBIndicator = true;
}else{
PBIndicator = false;
}
}
}
I'm inferring you're intending to use bindings by the use of OnPropertyChanged, so it's a good time to start do it.
I've made some changes in your code and I guess it will work properly now. The changes are:
Moved the layout creation to the constructor (I can't see create the whole same layout on every time the page is shown as a good choice );
The OnClicked event just invert the value of the property, no need to check it before with an if;
Using Bindings to handle the ActivityIndicator's properties state;
Set true to PBIndicator property on the OnAppearing event.
This is the changed code:
public partial class PBTestPage : ContentPage
{
private bool _pbIndicator;
public bool PBIndicator
{
get { return _pbIndicator; }
set
{
_pbIndicator = value;
OnPropertyChanged();
}
}
public PBTestPage()
{
InitializeComponent();
var parentLayout = new AbsoluteLayout();
var stackContent = new StackLayout();
AbsoluteLayout.SetLayoutFlags(stackContent, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(stackContent, new Rectangle(0f, 0f, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
var activityIndicator = new ActivityIndicator
{
Color = Color.Black
};
activityIndicator.SetBinding(ActivityIndicator.IsRunningProperty, new Binding(nameof(PBIndicator)));
activityIndicator.SetBinding(ActivityIndicator.IsVisibleProperty, new Binding(nameof(PBIndicator)));
activityIndicator.BindingContext = this;
AbsoluteLayout.SetLayoutFlags(activityIndicator, AbsoluteLayoutFlags.PositionProportional);
AbsoluteLayout.SetLayoutBounds(activityIndicator, new Rectangle(.5, .5, AbsoluteLayout.AutoSize, AbsoluteLayout.AutoSize));
var button = new Button
{
Text = "Click",
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.CenterAndExpand,
};
button.Clicked += OnClicked;
stackContent.Children.Add(button);
parentLayout.Children.Add(stackContent);
parentLayout.Children.Add(activityIndicator);
Content = parentLayout;
}
protected override void OnAppearing()
{
base.OnAppearing();
PBIndicator = true;
}
private void OnClicked(object sender, EventArgs e)
{
PBIndicator = !PBIndicator;
}
}
Let me know if it works. I hope it helps.
Try this one
private void OnClicked(object sender, EventArgs e)
{
if(PBIndicator==false){
activityIndicator.IsRunning=true;
}else{
activityIndicator.IsRunning=false;
}
}

Refresh ListView on another Content Page via button click event

I am having a hard time refreshing a listView. I've tried using ObservableCollection instead of List for contacts but it didn't help. Can someone points me to the right direction please? Any help would be very much appreciated.
ContactListPage.cs file (This is the default page. Add Contact button loads up NewContactPage.)
public class ContactListPage : ContentPage
{
public ListView listView = new ListView();
public List<Contact> contacts { get; set; }
public ContactListPage()
{
Button button = new Button
{
Text = "Add Contact",
Margin = new Thickness(0, 0, 10, 0)
};
button.Clicked += OnButtonClicked;
StackLayout buttonLayout = new StackLayout { Orientation = StackOrientation.Horizontal, VerticalOptions = LayoutOptions.Center,
Children =
{
new Label {Text = "Contact List", FontSize = 30, FontAttributes = FontAttributes.Bold | FontAttributes.Italic, Margin = new Thickness(10,0,0,0)},
new Label {Text = "", FontSize = 30, FontAttributes = FontAttributes.Bold | FontAttributes.Italic, HorizontalOptions = LayoutOptions.CenterAndExpand},
button
}
};
contacts = new List<Contact>
{
// Add some contacts
new Contact("Jason", "Bourne", "Family"),
new Contact("Sunny", "An", "Family Dog"),
new Contact("Jenny", "Bahn", "Family"),
new Contact("Joshua", "Brown", "Work")
};
// Set up listview
listView.ItemsSource = contacts;
listView.ItemTemplate = new DataTemplate(typeof(TextCell));
listView.ItemTemplate.SetBinding(TextCell.TextProperty, "FullName");
listView.ItemTemplate.SetBinding(TextCell.DetailProperty, "ContactType");
listView.HeightRequest = (40 * contacts.Count);
// Add things to the stacklayout
StackLayout layout = new StackLayout();
layout.Children.Add(buttonLayout);
layout.Children.Add(listView);
Content = layout;
void OnButtonClicked(object sender, EventArgs args)
{
Navigation.PushAsync(new NewContactPage());
};
}
}
Contact.cs file
public class Contact
{
// constructor
public Contact(string firstName, string lastName, string contactType)
{
FirstName = firstName;
LastName = lastName;
ContactType = contactType;
}
// properties
public string FirstName { get; set; }
public string LastName { get; set; }
public string ContactType { get; set; }
public string FullName
{
get
{
return FirstName + " " + LastName;
}
set
{
FullName = value;
}
}
}
NewContactPage.cs file (Save button seems to be working. I've used Debug.WriteLine to see the list of contacts prior and after adding a new contact. Return button suppose to refresh the contactPage.listView.ItemSource with the latest contents of contacts but it doesn't.)
public NewContactPage()
{
ContactListPage contactPage = new ContactListPage();
// Setup tableview
EntryCell firstName = new EntryCell {Label = "First Name:", Keyboard = Keyboard.Default};
EntryCell lastName = new EntryCell {Label = "Last Name:", Keyboard = Keyboard.Default};
EntryCell contactType = new EntryCell {Label = "Contact Type:", Keyboard = Keyboard.Default};
Label firstLabel = new Label { Text = "", FontSize = 10, FontAttributes = FontAttributes.Bold | FontAttributes.Italic, HorizontalOptions = LayoutOptions.CenterAndExpand};
Label secondLabel = new Label {Text = "", FontSize = 10, FontAttributes = FontAttributes.Bold | FontAttributes.Italic, HorizontalOptions = LayoutOptions.CenterAndExpand};
TableView tableView = new TableView {VerticalOptions = LayoutOptions.Start, Intent = TableIntent.Form,
Root = new TableRoot("Table Title") {
new TableSection ("Add a New Contact") {
firstName,
lastName,
contactType
}
}
};
// Setup buttons
Button saveContactButton = new Button {Text = "Save Contact", WidthRequest = 150, Margin = new Thickness(50, 0, 0, 0)};
saveContactButton.Clicked += saveContactButtonClicked;
Button returnButton = new Button {Text = "Return", WidthRequest = 150, Margin = new Thickness(10, 0, 50, 0)};
returnButton.Clicked += returnButtonClicked;
StackLayout buttonLayout = new StackLayout {Orientation = StackOrientation.Horizontal, VerticalOptions = LayoutOptions.Start,
Children =
{
saveContactButton,
new Label {Text = "", FontSize = 30, FontAttributes = FontAttributes.Bold | FontAttributes.Italic, HorizontalOptions = LayoutOptions.CenterAndExpand},
returnButton
}
};
Content = new StackLayout {Children = { tableView, buttonLayout, firstLabel, secondLabel }};
void saveContactButtonClicked(object sender, EventArgs e)
{
try
{
foreach (var yeah in contactPage.contacts)
{
Debug.WriteLine(yeah.FirstName.ToString());
}
// Add new contact to list
contactPage.contacts.Add(new Contact(firstName.Text.ToString(), lastName.Text.ToString(), contactType.Text.ToString()));
foreach (var yeah in contactPage.contacts)
{
Debug.WriteLine(yeah.FullName.ToString());
}
firstName.Text = String.Empty;
lastName.Text = String.Empty;
contactType.Text = String.Empty;
DisplayAlert("Success", "New contact has been added.", "OK");
}
catch(Exception ex)
{
Debug.WriteLine("Exception: {0}", ex);
}
};
void returnButtonClicked(object sender, EventArgs e)
{
contactPage.listView.ItemsSource = null;
contactPage.listView.ItemsSource = contactPage.contacts;
Navigation.PopAsync();
};
}
}
As Jason said, in the constructor of NewContactPage you are creating a new instance of ContactListPage which is completely different than the page you came from (and will return to upon PopAsync()).
To make it so you are adding the new contact to the correct page, I suggest passing in the your ContactListPage in the constructor of the NewContactPage:
public NewContactPage(ContactListPage contactPage)
{
//As a side note it's probably better practice to make
//contactPage a private variable for the NewContactPage class
//...
}
Then in your ContactListPage change the button click method to pass in the page:
void OnButtonClicked(object sender, EventArgs args)
{
Navigation.PushAsync(new NewContactPage(this));
};
Hope this helps!

How to set Datepicker default index is string value

I want to show datepicker default index value is string but I am not able to do that. Please suggest any idea. Thanks in advance.
I want to show picker like this:
You can use a UITextField and add date picker as a Input vie. And set PlaceHolder as "Date" or any string you want.
Sample Code
UITextField TextInput = new UITextField();
TextInput.Frame = new CGRect(40, 280, View.Frame.Width - 80, 40);
TextInput.Placeholder = "Date";
var picker = new UIDatePicker();
TextInput.InputView = picker;
Here is an example how to do it in ViewCell. You can use similar idea with View
public class TimePickerInCellPage : ContentPage
{
private ListView _listView;
public TimePickerInCellPage()
{
_listView = new ListView
{
RowHeight = 80,
SeparatorColor = Color.Blue,
SeparatorVisibility = SeparatorVisibility.Default
};
_listView.ItemsSource = new List<TaskTime>() {
new TaskTime { Id=1, StartTime=TimeSpan.FromHours(3) } ,
new TaskTime { Id=1, StartTime=TimeSpan.FromHours(5) } ,
new TaskTime { Id=1, StartTime=TimeSpan.FromHours(7) } ,
};
_listView.ItemTemplate = new DataTemplate(typeof(MyCell));
Content = new StackLayout
{
VerticalOptions = LayoutOptions.FillAndExpand,
Children = { _listView }
};
}
}
public class TaskTime
{
public int Id { get; set; }
public string Task { get; set; }
public TimeSpan StartTime { get; set; }
}
class MyCell : ViewCell
{
private readonly DatePicker _myTimePicker;
//private readonly TimePicker _myTimePicker;
public MyCell()
{
//_myTimePicker = new TimePicker()
_myTimePicker = new DatePicker()
{
HorizontalOptions = LayoutOptions.EndAndExpand
};
//_myTimePicker.Format = "HH:mm:ss";
_myTimePicker.Format = "dd:MM:yy HH:mm:ss";
_myTimePicker.SetBinding(TimePicker.TimeProperty, "StartTime");
_myTimePicker.PropertyChanged += MyTimePicker_PropertyChanged;
//_myTimePicker.Focused += _myTimePicker_Focused;
var viewLayout = new StackLayout()
{
HorizontalOptions = LayoutOptions.StartAndExpand,
Orientation = StackOrientation.Horizontal,
Padding = new Thickness(20),
Children = { _myTimePicker }
};
View = viewLayout;
}
bool firstTimeSet; //set when initial binding happens
//private void _myTimePicker_Focused(object sender, FocusEventArgs e)
//{
// firstTimeSet=true;
//}
private void MyTimePicker_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
//if (e.PropertyName == TimePicker.TimeProperty.PropertyName)
if (e.PropertyName == DatePicker.DateProperty.PropertyName)
{
if (!firstTimeSet)
firstTimeSet = true;
else
{
int x = 0;
string s = _myTimePicker.Date.ToString("dd/MM/yy HH:mm:ss");
}
}
}
}

Xamarin Forms - retrieve value of dynamically added entry control value on button click

I want to get all entry controls value on button click.
My code is as below - this is how I am adding dynamic control on page:
public BookSeat()
{
ScrollView scroll = new ScrollView();
StackLayout stack = new StackLayout();
int count = Convert.ToInt32(Application.Current.Properties["NoPersonEntry"]);
for (int i = 0; i < count; i++)
{
stack.Children.Add(
new StackLayout()
{
Children = {
new Label (){TextColor = Color.Blue, Text = "First Name: ", WidthRequest = 100,StyleId="FnameLabel"+i },
new Entry() {StyleId="FnameEntry"+i }
}
}
);
}
Button button = new Button
{
Text = "Save"
};
button.Clicked += OnButtonClicked;
stack.Children.Add(button);
scroll.Content = stack;
this.Content = scroll;
}
And below code is for I want to get value on button click
public void OnButtonClicked(object sender, EventArgs e)
{
// Here I want to get value
}
What you can do is to store your entries in a list so that you can access them later on.
For example :
private List<Entry> _myentries = new List<Entry>();
public BookSeat()
{
ScrollView scroll = new ScrollView();
StackLayout stack = new StackLayout();
int count = Convert.ToInt32(Application.Current.Properties["NoPersonEntry"]);
for (int i = 0; i < count; i++)
{
var entry = new Entry() {StyleId="FnameEntry"+i };
_myentries.Add(entry);
stack.Children.Add(
new StackLayout()
{
Children = {
new Label (){TextColor = Color.Blue, Text = "First Name: ", WidthRequest = 100,StyleId="FnameLabel"+i },
entry
}
}
);
}
[...]
}
Now you can do this :
public void OnButtonClicked(object sender, EventArgs e)
{
foreach(var entry in _myentries)
{
var text = entry.Text;//here we go
}
}

Resources