callback of Itemselected doesn't work in Xamarin? - xamarin

I have a simple two pages.
One has a listview.
So when clicks an item of the listView, go to another page.
But I click default back button on my win phone then I click an item of one again, navigation page doesn't work completely.
Here is my code snippet.
in first page
listview.itemselected += listview_ItemSelected;
private void listview_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
if (e.SelectedItem = null){
}
else {
Device.BeginInvokeOnMainThread(() => Navigation.PushAsync(new twopage()));
}
}
Please be aware that I am testing on UWP Project based on Xamarin.Form.

MainPage
Page1
this is my screen short
step 1
public App()
{
InitializeComponent();
var mainpage = new NavigationPage(new MainPage());
MainPage = mainpage;
}
step2
private void ListView_ItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var page = new Page1();
Navigation.PushAsync(page);
}

Related

Xamarin Modal Page Transition to Normal Page

Xamarin is having default page transition animation. Modal Page from bottom to top and Normal Page from right to left. Is there a way to apply modal page transition animation to a normal page.
I tried various CATransition animation in iOS using NavigationPageRenderer. I am not able to match the exact modal page animation provided by xamarin default.
protected override Task<bool> OnPushAsync(Page page, bool animated)
{
var type = page.GetType();
if (Startup.Instance.ModalPages.Contains(type))
{
var transition = CATransition.CreateAnimation();
transition.Duration = 0.5f;
transition.Type = CAAnimation.TransitionMoveIn; //tried other animation transitions
transition.Subtype = CAAnimation.TransitionFromTop;
View.Layer.AddAnimation(transition, null);
return base.OnPushAsync(page, false);
}
else
{
return base.OnPushAsync(page, animated);
}
}
protected override Task<bool> OnPopViewAsync(Page page, bool animated)
{
var type = page.GetType();
if (Startup.Instance.ModalPages.Contains(type))
{
var transition = CATransition.CreateAnimation();
transition.Duration = 0.5f;
transition.Type = CAAnimation.TransitionReveal;
transition.Subtype = CAAnimation.TransitionFromBottom;
View.Layer.AddAnimation(transition, null);
return base.OnPopViewAsync(page, false);
}
else
{
return base.OnPopViewAsync(page, animated);
}
Thanks
Is there a way to apply modal page transition animation to a normal page.
If just want to keep the same TransitionStyle with navigation of normal page. You can hide the NavigationBar when PushAsync , and not need to use PushModelAsync .
For example , Button_Clicked method of MainPage as follow :
private void Button_Clicked(object sender, EventArgs e)
{
Navigation.PushAsync(new PageTwo());
}
Then PageTwo :
public partial class PageTwo : ContentPage
{
public PageTwo()
{
InitializeComponent();
NavigationPage.SetHasNavigationBar(this, false);
}
private void Button_Clicked(object sender, EventArgs e)
{
Navigation.PopAsync();
}
}
The effect should be your want :
============================Update===================================
If need to use PushModelAsync , there is a workaround to achieve that effect .
Create a CustomPageRenderer for PageTwo in iOS solution :
[assembly: ExportRenderer(typeof(PageTwo), typeof(CustomPageRenderer))]
namespace XamarinMoelNavigationStyle.iOS
{
public class CustomPageRenderer :PageRenderer
{
public override void ViewWillAppear(bool animated)
{
var transition = CATransition.CreateAnimation();
transition.Duration = 0.5f;
transition.Type = CAAnimation.TransitionPush;
transition.Subtype = CAAnimation.TransitionFromRight;
View.Layer.AddAnimation(transition, null);
base.ViewWillAppear(animated);
}
}
}
We will add animation inside ViewWillAppear method .
When poping to previous MainPage , we can deal with that in ContentPage as follow :
private void Button_Clicked(object sender, EventArgs e)
{
PageTwoView.TranslateTo(300, 0, 500);
Device.StartTimer(TimeSpan.FromSeconds(0.5), () =>
{
// Do something
Navigation.PopModalAsync(false);
return false; // True = Repeat again, False = Stop the timer
});
}
Here PageTwoView is defined from Xaml :
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Name="PageTwoView"
x:Class="XamarinMoelNavigationStyle.PageTwo">
...
</ContentPage>
Note : When MainPage navigate to PageTwo , need to disable the animation .
Such as :
private void Button_Clicked(object sender, EventArgs e)
{
Navigation.PushModalAsync(new PageTwo(), false);
}
The effect :

How can I open another activity using spinner item selection in xamarin.forms only?

I've tried this and it looks like majority of search results reference to Android studio. I'm using visual studio, xamarin forms.
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
SetContentView (Resource.Layout.Main);
Spinner spinner = FindViewById<Spinner> (Resource.Id.spinner);
spinner.ItemSelected += new EventHandler<AdapterView.ItemSelectedEventArgs> (spinner_ItemSelected);
var adapter = ArrayAdapter.CreateFromResource (
this, Resource.Array.my_array, Android.Resource.Layout.SimpleSpinnerItem);
adapter.SetDropDownViewResource (Android.Resource.Layout.SimpleSpinnerDropDownItem);
spinner.Adapter = adapter;
}
The spinner loads perfectly but the item selected method opens the activity on loading.
private void spinner_ItemSelected (object sender, AdapterView.ItemSelectedEventArgs e)
{
SetContentView (Resource.Layout.page1);
}
How best can I load the activity on specific item selection. Note: the items are referenced in the Strings.xml.
Because Spinner chooses the first item by default when initialized, it will fire spinner_ItemSelected
You can add a conditional judgment to your spinner_ItemSelected method:
private void spinner_ItemSelected (object sender, AdapterView.ItemSelectedEventArgs e)
{
var index = e.Parent.SelectedItemPosition; //base on the select position
var obj = e.Parent.SelectedItem; // base on the selectitem value(string)
// xxx is your conditions
if(index == xxx)
{
SetContentView (Resource.Layout.page1);
}
// or
if(obj.ToString().Equals("xxx"))
{
SetContentView (Resource.Layout.page1);
}
}

How do I control the content page focus?

I have a listview data on ItemsPage and when I select an item I can edit it and will update on database. My problem is, when a go back to ItemsPage I want to refresh the list
I already tried to call the method OnAppearing to try to refresh in OnItemSelected under the Navigation like this:
namespace TesteMasterDatail.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class ItemsPage : ContentPage
{
ItemsViewModel viewModel;
public ItemsPage()
{
InitializeComponent();
BindingContext = viewModel = new ItemsViewModel();
}
async void OnItemSelected(object sender, SelectedItemChangedEventArgs args)
{
var item = args.SelectedItem as Item;
if (item == null)
return;
await Navigation.PushAsync(new ItemDetailPage(new ItemDetailViewModel(item)));
OnAppearing();
ItemsListView.SelectedItem = null;
}
async void AddItem_Clicked(object sender, EventArgs e)
{
await Navigation.PushModalAsync(new NavigationPage(new NewItemPage()));
}
protected override void OnAppearing()
{
base.OnAppearing();
if (viewModel.Items.Count == 0)
viewModel.LoadItemsCommand.Execute(null);
}
}
}
It didnt work cause the refresh happens before the edition
you could use MessagingCenter to refresh your list after you add new item or edit item in a new page like:
in ItemsPage :
public ItemsPage()
{
InitializeComponent();
BindingContext = viewModel = new ItemsViewModel();
MessagingCenter.Subscribe<ItemsPage> (this, "Refresh", () =>
{
// refresh the list when the "Refresh" message is received
});
}
in ItemDetailPage or NewItemPage,after edit item or add new item:
MessagingCenter.Send<ItemsPage>(this, "Refresh");
Of course you could also pass parameter by MessagingCenter
OnAppearing() should be called for you when the page is navigated to after PopAsync is called - you do not need to manually call it.
However, note that your LoadItemsCommand will still not fire in this case, because the VM is already initialized.
from the docs
When the PopAsync method is invoked, the following events occur:
-The page calling PopAsync has its OnDisappearing override invoked.
-The page being returned to has its OnAppearing override invoked.
-The PopAsync task returns.

Xamarin Forms ToolbarItems shown on the wrong page

I have an Issue with the ToolbarItems.
So i start my application and in the constructor I check if somebody clicked on an element from the listview which is on my main page. If that happens, I'll start a new page. The error I have is that the toolbaritems from the mainpage are still displayed now.
Here this is the Method I use in the constructor :)
public void LoadLastPortal() {
if (App.Current.Properties.ContainsKey("LastPortal"))
{
String LastPortal = App.Current.Properties["LastPortal"].ToString();
if (!string.IsNullOrEmpty(LastPortal))
{
Navigation.PushAsync(new LoginPage(App.Current.Properties["LastPortal"].ToString()));
}
}
I've tried to reproduce your issue, but in my sample app it works. See here the code for the MainPage:
public MainPage()
{
InitializeComponent();
this.ToolbarItems.Add(new ToolbarItem { Text = "test1" });
this.ToolbarItems.Add(new ToolbarItem { Text = "test2" });
this.ToolbarItems.Add(new ToolbarItem { Text = "test3" });
}
private void NavigateButtonOnClicked(object sender, EventArgs e)
{
Navigation.PushAsync(new SecondPage());
}
After I pressed the Button on the MainPage I'm navigating to the SecondPage and the three ToolbarItems aren't shown. Please provide some more information, so I'm able to help you.

ListBox and selectedIndexChanged event after the user hit the back button

In my windows phone 7 app, I have the following code to handle the OnSelectedIndexChange of a ListBox.
private void wordList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
WordList selectedList = (WordList)e.AddedItems[0];
NavigationService.Navigate(new Uri("/Views/Game.xaml?ListName=" + selectedList.Name, UriKind.RelativeOrAbsolute));
}
The above code work fine, However if the user click on the hardware back button from the Game page, and click on the same listbox item, the above code is not called. I assume this is because the selected item is the same therefore the SelectionChanged event is not being called.
How do I make it so that if the user select the same item I can still send them to the Game page?
I looked at the Tap Event but I couldn't figure out a way to get the selected Item from the tab event.
When using SelectionChanged to navigate, surround your navigation logic with a check to see if the SelectedIndex = -1. After you navigate, set the index to -1, so that the event will not fire twice.
private void wordList_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
var lb = sender as ListBox;
if (lb != null)
{
if (lb.SelectedIndex == -1) return;
WordList selectedList = (WordList)e.AddedItems[0];
NavigationService.Navigate(new Uri("/Views/Game.xaml?ListName=" + selectedList.Name, UriKind.RelativeOrAbsolute));
lb.SelectedIndex = -1;
}
}
This way you can get the selected Item from the Tap event.
private void wordList_Tap(object sender, GestureEventArgs e)
{
var selectedElement = e.OriginalSource as FrameworkElement;
if (selectedElement != null)
{
var selectedData = selectedElement.DataContext as WordList;
if (selectedData != null)
{
NavigationService.Navigate(new Uri("/Views/Game.xaml?ListName=" + selectedData.Name, UriKind.RelativeOrAbsolute));
}
}
}
I had such issue within a UserControl. Check the sender, and return if it is not the ListBox control which is triggering the event:
protected void cbEvents_SelectedIndexChanged(object sender, EventArgs e)
{
if (sender is DropDownList)
RebindGrid();
}

Resources