Capture Tab Click Event in Mono - xamarin.android

I have a Tabhost in my app with 3 tabs. The tabs are all working fine.
Now I want to perform some additional logic when the tab is selected?.
For Example: In one of my tabs, I provide an option for the user to sort things in different order and update the another tab.
how can we get the click event of TabHost?
I have updated the Tab Creation (Activity) part.
Thanks in Advance.
[Activity(Label = "My Activity")]
public class TabSearch : TabActivity
{
protected override void OnCreate(Bundle bundle)
{
try
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Search_WOTab);
/* ******************** Adding 2 Tab Controls and setting Activity classes to Tabs added ******************** */
TabHost.TabSpec tspec;
Intent intent;
intent = new Intent(this, typeof(WOSearch));
intent.AddFlags(ActivityFlags.NewTask);
tspec = TabHost.NewTabSpec("Search");
tspec.SetIndicator("Search", Resources.GetDrawable(Resource.Drawable.Search));
tspec.SetContent(intent);
TabHost.AddTab(tspec);
intent = new Intent(this, typeof(WOFilter));
intent.AddFlags(ActivityFlags.NewTask);
tspec = TabHost.NewTabSpec("Filter");
tspec.SetIndicator("Filter", Resources.GetDrawable(Resource.Drawable.Filter));
tspec.SetContent(intent);
TabHost.AddTab(tspec);
TabHost.TabChanged += (sender, e) =>
{
Toast.MakeText(this, TabHost.CurrentTab.ToString(), ToastLength.Short).Show();
};
}
catch (Exception ex)
{
Toast.MakeText(this, ex.InnerException.ToString(), ToastLength.Short);
}
}

You can use the TabHost.TabChanged event.
tabHost.TabChanged += (sender, e) => {
if (tabHost.CurrentTab == 0) {
// Do what you want.
}
};
PS: Xamarin Docs is your friend.
Edit:
You should modify your code to this...
//TabHost.TabChanged += TabHost_TabChanged;
TabHost.TabChanged += (sender, e) =>
{
Toast.MakeText(this, TabHost.CurrentTab.ToString(), ToastLength.Short).Show();
};
TabHost.CurrentTab is the index of the selected tab.

Related

How to navigate to a different content page after a function is called

I have an app that has 2 tabs in Xamarin forms (iOS side). I'd like to know how to make my app navigate to a different content page after a function is called. Let me show you what I mean in code:
these are my two functions in my content page:
protected override async void OnAppearing()
{
base.OnAppearing();
TakePhotoButton_Clicked();
}
async void TakePhotoButton_Clicked()
{
if (App.pictureTaken) return;
App.pictureTaken = true;
//Allows users to take pictures in the app
if (!CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
{
DisplayAlert("No Camera", "Camera is not available.", "OK");
return;
}
var file = await CrossMedia.Current.TakePhotoAsync(new Plugin.Media.Abstractions.StoreCameraMediaOptions
{
//Sets the properties of the photo file
SaveToAlbum = true,
PhotoSize = PhotoSize.MaxWidthHeight,
DefaultCamera = CameraDevice.Rear
});
if (file == null)
return;
}
After calling the TakePhotoButton_Clicked() I'd like to force my app to navigate to my other content page.
in pseudocode it would look like:
NavigateTo(MyOtherContentPage);
But im not sure how that would work or if something like that exists. Any suggestions?
Welcome to SO!
If Root page of MainPage is NavigationPage , such as: MainPage = new NavigationPage (new Page1Xaml ()); , you can use Navigation.PushAsync to navigate to another page as follow :
async void OnNextPageButtonClicked (object sender, EventArgs e)
{
await Navigation.PushAsync (new Page2Xaml ());
}
Else if Root page is a normal Page, you can use model naivgation method to navigate to another page as follow:
async void OnItemSelected (object sender, SelectedItemChangedEventArgs e)
{
...
await Navigation.PushModalAsync (detailPage);
}
}
More info can refer to Performing Navigation and Pushing Pages to the Modal Stack.

Navigation Stack not cleared after calling RemovePage in iOS - Xamarin.Forms

I am currently developing app using Xamarin.Forms. I am facing some serious issue in iOS. My root page is TabbedPage and I want to make my tabs visible for entire applications. Hence I am setting MainPage as below
App.cs
MainPage = new NavigationPage(new MyTabbedPage());
MyTabbedPage.cs
Children.Add(new NavigationPage(new FirstTabbedPage()));
Children.Add(new NavigationPage(new SecondTabbedPage()));
Children.Add(new NavigationPage(new ThirdTabbedPage()));
Both FirstTabbedPage & SecondTabbedPage shows DataGrid using DevExpress.Mobile. On tap of any row from the Grid I am Navigating to another ContentPage say MyContentPage within the Root Tab.
SecondTabbePage.cs
private async void Grid_RowTap(object sender, RowTapEventArgs e)
{
//Some code logic, to get data from server
await Navigation.PushAsync(new MyContentPage());
}
For Example I am navigating to MyContentPage from SecondTabbedPage. From ContentPage I am Navigating to FirstTabbedPage. Now if I click SecondTabbedPage, MyContentPage will be shown, but I don't want this behaviour hence I am removing the page from NavigationStack in OnDisappearing method of MyContentPage as below:
MyContentPage.cs
protected override void OnDisappearing()
{
base.OnDisappearing();
//Clear Navigation Stack, clicking on tab page should always
//go to corresponding page
try
{
var existingPages = Navigation.NavigationStack.ToList();
foreach (var page in existingPages)
{
//existingPages count should be greater than 1, so that this will never be root page. Otherwise removing root page will throw exception
if (string.Compare(page.GetType().Name, "MyContentPage", StringComparison.OrdinalIgnoreCase) == 0 && existingPages.Count > 1)
{
Navigation.RemovePage(page);
}
}
//Just to check whether page was removed or not, but still was able to see MyContentPage even after removing it from Navigation Stack
var existingPages = Navigation.NavigationStack.ToList();
}
catch(Exception ex)
{
}
}
Now the issues are:
Even after calling RemovePage(MyContentPage) I am able to see that page in Debug mode.
Due to this behaviour await Navigation.PushAsync(new MyContentPage()); is not navigating to MyContentPage second time even-though it executes code without any exception.
The same code is working fine in Android as Android life cycle is
different which I was able to see in Debug mode
Few Things I Tried Are:
Removed NavigationPage from MainPage (TabbedPage) as I read that TabbedPage inside NavigationPage is not good design for iOS.
Removed NavigationPage on Child Items but tabbed icons were not shown after navigating to MyContentPage
Tried removing MyContentPage from NavigationStack in OnAppearing event of FirstTabbedPage.
As you said, due to the Android life cycle is different from iOS, I would recommend you to achieve the requirement by using custom renderer in iOS.
You should create a custom renderer of your MyTabbedPage, and then in ViewControllerSelected event, remove your ContentPage from NavigationStack.
[assembly: ExportRenderer(typeof(MainPage), typeof(myTabbarRenderer))]
namespace TabbedPageWithNavigationPage.iOS
{
class myTabbarRenderer : TabbedRenderer
{
private MainPage _page;
protected override void OnElementChanged(VisualElementChangedEventArgs e)
{
base.OnElementChanged(e);
if (e.NewElement != null)
{
_page = (MainPage)e.NewElement;
}
else
{
_page = (MainPage)e.OldElement;
}
try
{
var tabbarController = (UITabBarController)this.ViewController;
if (null != tabbarController)
{
tabbarController.ViewControllerSelected += OnTabbarControllerItemSelected;
}
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
private async void OnTabbarControllerItemSelected(object sender, UITabBarSelectionEventArgs eventArgs)
{
if (_page?.CurrentPage?.Navigation != null && _page.CurrentPage.Navigation.NavigationStack.Count > 0)
{
await _page.CurrentPage.Navigation.PopToRootAsync();
}
}
}
}
And for Android, add Device.RuntimePlatform == Device.Android to make sure the code only works on Android platform:
protected override void OnDisappearing()
{
base.OnDisappearing();
//Clear Navigation Stack, clicking on tab page should always
//go to corresponding page
if (Device.RuntimePlatform == Device.Android)
{
try
{
var existingPages = Navigation.NavigationStack.ToList();
foreach (var page in existingPages)
{
//existingPages count should be greater than 1, so that this will never be root page. Otherwise removing root page will throw exception
if (string.Compare(page.GetType().Name, "UpcomingAppointmentsPage", StringComparison.OrdinalIgnoreCase) == 0 && existingPages.Count > 1)
{
Navigation.RemovePage(page);
}
}
}
catch (Exception ex)
{
}
}
}
I write a demo here and you can check it. Let me know if it works.
I tried #Jackhua solution. It works perfect as well. But I used following way to fix the above problem as suggested in Xamarin Forum.
Reference: https://forums.xamarin.com/discussion/comment/375638#Comment_375638
MyTabbedPage.cs
Page page1 = null;
Page page2 = null;
Page page3 = null;
public MainPage()
{
InitializeComponent();
page1 = new NavigationPage(new FirstTabbedPage());
page1.Title = "Page1";
page2 = new NavigationPage(new SecondTabbedPage());
page2.Title = "Page2";
page3 = new NavigationPage(new ThirdTabbedPage());
page3.Title = "Page3";
Children.Add(page1);
Children.Add(page2);
Children.Add(page3);
}
protected override void OnCurrentPageChanged()
{
base.OnCurrentPageChanged();
int index = Children.IndexOf(CurrentPage);
if (index == 0)
{
if (Children.Count > 1)
{
page2 = Children[1] as NavigationPage;
page2.Navigation.PopToRootAsync();
page3 = Children[2] as NavigationPage;
page3.Navigation.PopToRootAsync();
}
}
else if (index == 1)
{
if (Children.Count > 1)
{
page1 = Children[0] as NavigationPage;
page1.Navigation.PopToRootAsync();
page3 = Children[2] as NavigationPage;
page3.Navigation.PopToRootAsync();
}
}
else if (index == 2)
{
if (Children.Count > 1)
{
page1 = Children[0] as NavigationPage;
page1.Navigation.PopToRootAsync();
page2 = Children[1] as NavigationPage;
page2.Navigation.PopToRootAsync();
}
}
}
Above solution doesn't require Custom Renderer and works for both Android & iOS.
Also code block under MyContentPage.cs is not required. i.e
remove iterating of existingPages under OnDisappearing method

Change Switch color in IOS Xamarin Forms

How to change the color of the switch button when toggling for IOS Xamarin Forms? Custom render will set the color just once:
Xamarin forms toggle button default color on IOS
and it won't be changed when the Switch is toggled. Same goes and for setting values in AppDelegate.cs it will be done only once. I need this:
In IOS its only possible using:
UISwitch.Appearance.ThumbTintColor = UIColor.Brown;
UISwitch.Appearance.OnTintColor = UIColor.Red;
but how I can access that field if my switch is in PCL project, and its used for Xamarin Forms.
I solved this with:
public class CustomSwitchRenderer: SwitchRenderer
{
protected override void OnElementChanged(ElementChangedEventArgs<Switch> e)
{
Element.Toggled += ElementToggled;
base.OnElementChanged(e);
if (Control != null)
{
UpdateUiSwitchColor();
}
}
private void ElementToggled(object sender, ToggledEventArgs e)
{
UpdateUiSwitchColor();
}
private void UpdateUiSwitchColor()
{
var temp = Element as Switch;
if (temp.IsToggled)
{
Control.ThumbTintColor = Color.FromHex(ColorConstants.BlueHex).ToUIColor();
Control.OnTintColor = Color.FromHex(ColorConstants.OblueLightHex).ToUIColor();
}
else
{
Control.ThumbTintColor = Color.FromHex(ColorConstants.GrayHex).ToUIColor();
}
}
}
So, I activated event whenever Toggle is executed:
Element.Toggled += ElementToggled;
You can still do it in a custom renderer. Just listen to the switch's ValueChanged event, there you can check if it is on or off, and update the color.
For example, in your iOS project's custom switch renderer class:
protected override void OnElementChanged(ElementChangedEventArgs<Switch> e)
{
base.OnElementChanged(e);
Control.ValueChanged += Control_ValueChanged;
}
private void Control_ValueChanged(object sender, EventArgs e)
{
if (Control.On)
{
// set on colors
}
else
{
// set off colors
}
}

Umbraco unpublish Event not working for the current node

I am developing Umbraco 7 MVC application and my requirement is to add Item inside Umbraco. Item name should be unique. For that used the below code but I am getting the error "Oops: this document is published but is not in the cache (internal error)"
protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication,
ApplicationContext applicationContext)
{
ContentService.Publishing += ContentService_Publishing;
}
private void ContentService_Publishing(IPublishingStrategy sender, PublishEventArgs<IContent> e)
{
try
{
if(newsItemExists)
{
e.Cancel = true;
}
}
catch (Exception ex)
{
e.Cancel = true;
Logger.Error(ex.ToString());
}
}
Then I tried adding code to unpublish but its not working i.e the node is getting published. Below is my code
private void ContentService_Publishing(IPublishingStrategy sender, PublishEventArgs<IContent> e)
{
try
{
int itemId=1234; //CurrentPublishedNodeId
if(newsItemExists)
{
IContent content = ContentService.GetById(itemId);
ContentService.UnPublish(content);
library.UpdateDocumentCache(item.Id);
}
}
catch (Exception ex)
{
e.Cancel = true;
Logger.Error(ex.ToString());
}
}
But with the above code, if you give the CurrentPublishedNodeId=2345 //someOthernodeId its unpublished correctly.
Can you please help me on this issue.
You don't have to do this, Umbraco will automatically append (1) to the name if the item already exists (so it IS unique).
If you don't want this behavior you can check in the following way:
protected override void ApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
ContentService.Publishing += ContentService_Publishing;
}
private void ContentService_Publishing(Umbraco.Core.Publishing.IPublishingStrategy sender, PublishEventArgs<IContent> e)
{
var contentService = UmbracoContext.Current.Application.Services.ContentService;
// It's posible to batch publish items, so go through all items
// even though there might only be one in the list of PublishedEntities
foreach (var item in e.PublishedEntities)
{
var currentPage = contentService.GetById(item.Id);
// Go to the current page's parent and loop through all of it's children
// That way you can determine if any page that is on the same level as the
// page you're trying to publish has the same name
foreach (var contentItem in currentPage.Parent().Children())
{
if (string.Equals(contentItem.Name.Trim(), currentPage.Name.Trim(), StringComparison.InvariantCultureIgnoreCase))
e.Cancel = true;
}
}
}
I think your problem might be that you're not looping through all PublishedEntities but using some other way to determine the current page Id.
Note: Please please please do not use the library.UpdateDocumentCache this, there's absolutely no need, ContentService.UnPublish will take care of the cache state.

I Want to display a listview when i click a button in Monodroid. i tried this coding. its not running. Can anyone correct this

I want to display a listview when I click a button in Monodroid. I tried the following code, however it doesn't run. Can anyone correct this?
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
SetContentView (Resource.Layout.Main);
Button button1 = FindViewById<Button> (Resource.Id.btn);
button1.Click += delegate { listviewFunction(); };
}
public void listviewFunction()
{
ListAdapter = new ArrayAdapter<string>(this, Resource.Layout.list_item, _countries);
ListView.TextFilterEnabled = true;
ListView.ItemClick += (sender, args) => Toast.MakeText(Application, ((TextView) args.View).Text, ToastLength.Short).Show();
}
Try just:
button1.Click += ...
Declare a ListView globally:
private ListView _listView;
Now (1)create the ListView, OR (2)get it from a axml file:
(1)
_listView = new ListView(this);
(2)
_listView = (ListView)View.FindViewById(Resource.Id.MyList);
Now create your adapter, then:
_listView.SetAdapter(myAdapter);
Then create your ItemClick handler:
_listView.ItemClick += (sender, args) => Toast.MakeText(Application, ((TextView) args.View).Text, ToastLength.Short).Show();

Resources