blank page when using pushasync xamarin - c#

how are you?
I created a top ContentPage class inheriting a ZXingScannerPage class to be able to create methods in order to better streamline the code. And in it a method that takes as a parameter a Label and a ContentPage to set the data read by the Scanner.
public String ScannResult { get; set; }
}
public class ScannerHelper : ZXingScannerPage
{
public ScannerHelper()
{
this.OnScanResult += (result) => {
MessagingCenter.Send( new Message { ScannResult = result.Text }, "ScannResult");
// Parar de escanear
this.IsScanning = false;
// Alert com o código escaneado
Device.BeginInvokeOnMainThread(() => {
DisplayAlert("Código escaneado", result.Text, "OK");
Navigation.PopAsync(false);
});
};
}
public static void teste(Label label, ContentPage contentPage)
{
MessagingCenter.Subscribe<Message>(contentPage, "ScannResult", message => {
label.Text = message.ScannResult;
});
}
}
}
So far everything is working, but when I call this class on a button and run it later, the screen takes the data and goes to the label, but when going to another page with a PushAsync the page is blank and if I go back to the pages and try to go to the next one it is blank and the strangest thing if I leave the app on my cell phone going to the menu and returning to it the page is normal. Example: Page A calls the Scanner and works, on Page A I go to Page B and it is blank, I go back to Page A and I go back to the page before Page A and then I go back to A to A and now it is in White.
Example of how I use the Methods on the buttons and on the page:
{
InitializeComponent();
ScannerHelper.teste(lblNomeProduto, this);
}
private void ButtonScanner(object sender, EventArgs e)
{
Navigation.PushAsync(new ScannerHelper());
}

Related

Navigate Content Pages MVVM xamarin

Can someone teach me how to navigate between pages of content? I have been reading many tutorials but I have not been able to achieve it. I have this small code I want to achieve that when pressing the buttons I change between the pages. I use MVVM model there is my MainViewModel
public class MainViewModel
{
public Page1 PageNumberOne { get; set; }
public Page2 PageNumberTwo { get; set; }
public MainViewModel()
{
this.PageNumberOne = new Page1();
}
}
there is my view model of Page1
public class Page1
{
#region constructor
public Page1()
{
GoPage2Command = new Command(async () => await GoPage2());
}
private async Task GoPage2()
{
await Application.Current.MainPage.DisplayAlert("", "Goin to page 2", "ok");
//code to go PageNumberTwo here
}
#endregion
#region Commands
public Command GoPage2Command { get; set; }
#endregion
}
GoPage2Command is binding to a button.
there is my complete project up load to MF VS proyect
Simply call
Navigation.PushAsync(new ContentPage());
INavigation.PushAsync Method
Asynchronously adds a Page to the top of the navigation stack.
Example from the page
var newPage = new ContentPage ();
await Navigation.PushAsync (newPage);
Debug.WriteLine ("the new page is now showing");
var poppedPage = await Navigation.PopAsync ();
Debug.WriteLine ("the new page is dismissed");
Debug.WriteLine (Object.ReferenceEquals (newPage, poppedPage)); //prints "true"
Your Exmaple
private async Task GoPage2()
{
await Application.Current.MainPage.DisplayAlert("", "Goin to page 2", "ok");
//code to go PageNumberTwo here
Navigation.PushAsync(new PageNumberTwo());
}
I found the problem, I was using Xamarin Live to do the tests, connecting by cable does not give any error. I do not recommend using Xamarin Live not only gives that problem but many more

Dynamically made pages don't load actual page content/code

I'm trying to create a modular way of loading pages, each page having it's own navigation menu item in the main window header and a separate frame to keep them always loaded in memory (and to play fancy animations etc.)
Here's the class that contains the loaded page.
public sealed class PageContainer : Frame
{
public string Title;
public PageContainer(string Page, bool CustomUri = false)
{
Visibility = System.Windows.Visibility.Collapsed;
NavigationUIVisibility = NavigationUIVisibility.Hidden;
Title = Page;
if(!CustomUri)
{
Navigate($"pack://lotus:,,,/Views/UserPages/{Page}.xaml", UriKind.Relative);
}
else
{
//todo
}
Console.WriteLine($"Navigation Item created {Title} with ?CustomUri: {CustomUri}");
}
public bool Visible
{
get => Visibility == System.Windows.Visibility.Visible;
set => Visibility = value ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
}
}
And here's how I'm creating the PageContainer(s)
Animations.PageTransitionAnimations AnimationLibrary;
public double _SlideAnimationLenght = 250;
public MainWindow()
{
InitializeComponent();
//Initialize Animation Library
AnimationLibrary = new Animations.PageTransitionAnimations(this);
InitializePage("Library");
InitializePage("Preferences");
InitializePage("Plugins");
InitializePage("Information");
foreach(PageContainer pp in LoadedContainers)
{
pp.Visible = true;
pp.BeginAnimation(MarginProperty, AnimationLibrary.ToLeft);
}
}
//Load a page and add it to navigation bar, if NoHeader, then don't add it to navigation
private void InitializePage(string page, bool noHeader = false)
{
if(!noHeader)
{
//Add page to navigation bar and set style
NavigationHeader.Children.Add(new NavigationItem(page)
{
Style = FindResource("HeaderMenu") as System.Windows.Style
});
}
//Add Page to PageContainer and Initialize it
PageContainer _page = new PageContainer(page);
_containers.Add(_page);
PagesContainer.Children.Add(_page);
}
//Public LoadedContainers, no setter
private List<PageContainer> _containers = new List<PageContainer>();
public List<PageContainer> LoadedContainers => _containers;
What happens is that the navigation in PageContainer actually succeeds the navigation event, but frames don't report any content, page code doesn't execute and there's no design.
Any suggestions? Thanks.
Edit:
Pages themselves have no problems, because I load them manually, they do work. Also, here's the link to full code: https://github.com/FaithLV/lotus
There was an issue with how I was navigating to the page.
Turns out, the "application" in URI wasn't context sensitive and actually is used as is.
Here's the correct way to navigation:
Navigate(new Uri($"pack://application:,,,/Views/UserPages/{Page}.xaml"), UriKind.Absolute);

Get result of an int changed in a ContentPage

I have an app with the following page structure:
MainPage
->SettingsPage
->InputLanguagePage
->OutputLanguagePage
All pages are ContentPages.
InputLanguagePage and OutputLanguagePage are the very same pages, so I don't want to program the very same page twice.
I can surely instantiate the same page twice, but I have no idea how I should get the return value.
I spent really long trying to describe my problem.
Perhaps the code below demonstrates the problem much better.
As you can see, I seem to be unable to get the return value of the LanguageSelectionPage since it's shown asynchronous.
Also changing it to Navigation.PushModalAsync() didn't change anything.
What would be the best way to have a ContentPage return a value or change a value and be notified about it?
Thank you.
MainPage:
public class MainPage : ContentPage
{
private async void OnSettingsSelected(object sender, EventArgs e)
{
SettingsPage nSettings = new SettingsPage();
await this.Navigation.PushAsync(nSettings);
}
(...)
SettingsPage:
public class SettingsPage : ContentPage
{
public SettingsPage()
{
protected override async void OnAppearing()
{
base.OnAppearing();
_btnInputLanguage.Clicked += async (sender, e) =>
{
LanguageSelectionPage nInputLanguage = new LanguageSelectionPage();
nInputLanguage.SelectedLCID = App.Settings.InputLanguageLCID;
await Navigation.PushAsync(nInputLanguage);
//The user can change "int SelectedLCID" within the ContentPage, but I have no idea how I could access it
return;
};
_btnOutputLanguage.Clicked += async (sender, e) =>
{
LanguageSelectionPage nOutputLanguage = new LanguageSelectionPage();
nOutputLanguage.SelectedLCID = App.Settings.OutputLanguageLCID;
await Navigation.PushAsync(nOutputLanguage);
//The user can change "int SelectedLCID" within the ContentPage, but I have no idea how I could access it
return;
};
(...)
LanguageSelectionPage:
public class LanguageSelectionPage : ContentPage
{
public int SelectedLCID { get; set; }
protected override async void OnAppearing()
{
base.OnAppearing();
(...)
I will give solutin to pass it ass parameter when yu ask to load page
public partial class InputLanguagePage : ContentPage
{
public InputLanguagePage(string Selection)
{
InitializeComponent();
}
}
public partial class OutputLanguagePage : ContentPage
{
public OutputLanguagePage(string Selection)
{
InitializeComponent();
}
}
In settingsPage Button Click
_btnInputLanguage.Clicked += async (sender, e) =>
{
Navigation.PushAsync(new InputLanguagePage ("SelectLanguage"));
return;
};
_btnOutputLanguage.Clicked += async (sender, e) =>
{
Navigation.PushAsync(new OutputLanguagePage("SelectLanguage"));
return;
};
There are a lot of ways to solve this:
pass a completion handler to the 2nd page
raise an event on the 2nd page and subscribe from the 1st page
pass an object whose value will be set by the 2nd page
use Messaging
*
// on the first page, listen for a message
MessagingCenter.Subscribe<SecondPage, string> (this, "ValueSet", (sender, arg) => {
// arg will contain the value passed by the sender
});
// when the value is set on the 2nd page, send a message
MessagingCenter.Send<SecondPage, string> (this, "ValueSet", someValue);

Xamarin. Different behavior app after resume

For my first project during learning xamarin I make simple app where user can create a note and add alarm time to schedule local notification.
I have a problem when app resume from background.
To the point.
Note model:
public class Note
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[MaxLength(255)]
public string Title { get; set; }
[MaxLength(255)]
public string Content { get; set; }
public DateTime TimeCreate { get; set; }
public DateTime AlarmTime { get; set; }
public bool AlarmTimeActive { get; set; }
}
In main page there is list of notes. Every note has a switch button where user can on/off time alarm.
If user try to switch on alarm, function check is schedule time gone or not. If gone then switch stay in off position and app display information. In other case function updates value in data base to "true".
XAML
<local:ButtonActiveSwitcher Toggled="Switch_Toggled" IsToggled="{Binding AlarmTimeActive}" Active="{Binding .}" />
function "Switch_Toggled"
private void Switch_Toggled(object sender, ToggledEventArgs e)
{
var switchBtn = sender as Switch;
var item = ((ButtonActiveSwitcher)sender).Active;
if (item != null)
{
if (item.AlarmTime < DateTime.Now)
{
if (_nooLoopTime.AddSeconds(2) < DateTime.Now) //Prevent double display alert
{
DisplayAlert("ALERT", "Time gone", "OK");
_nooLoopTime = DateTime.Now;
}
switchBtn.IsToggled = false;
return;
}
DataBaseService.updateRecord(item);
}
}
And this function works fine when user tapped switcher.
Next point.
In MainPage.cs in function OnAppearing app fired function DataBaseService.checkNoteAlarmTimeActive();. In this function app check AlarmTime in notes. If AlarmTimeActive is active but schedule time has gone then change AlarmTimeActive to "false".
First app checks Notes in DB and update them, next function loadNotes() getting Notes from DB and populate list.
So before app gets Notes from DB first update records in DB.
MainPage.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPage : ContentPage
{
private Sorting _sorting;
private int _sortOption;
private bool _activeSwitcherState;
private DateTime _nooLoopTime;
public MainPage(int noteid)
{
DataBaseService.CreateTables();
this._sorting = new Sorting();
InitializeComponent();
this.AddPickerItems();
if (noteid != 0)
{
this.loadNoteView(noteid);
}
}
protected async override void OnAppearing()
{
await DataBaseService.checkNoteAlarmTimeActive();
this.loadNotes();
base.OnAppearing();
}
/// <summary>
/// Generate list of notes basic on current sorting option and active switcher
/// </summary>
private async void loadNotes()
{
listNotes.ItemsSource = await _sorting.sortNotes(_sortOption, _activeSwitcherState);
}
}
And here is my problem.
For example: one Note has AlarmTimeActive "true" and user tapped "Home" button, app goes to background. Later when schedule alarm time has gone user put app to foreground by tapping app from list under App Switcher button. And for some reason app first display alert "Time gone" and latter (I think) do function OnAppearing(). Finally in main page I have a list of Notes with updated records, but why app displays this alert first?
But this problem doesn't appear in three other cases.
User kill app in App Switcher list and open again tapping icon in application list.
User exit from app tapped Back Button.
User resume app by tapping notification.
So why if user resume app from App Switcher list, this alert is displayed but in other cases not?
I hope my description is clear.
Please explain to me why it happens and how to fix it.
Try to avoid async void except for event handlers. OnAppearing is not an event handler. but is it called before the actual Appearing event, which gives you a chance to subscribe to it with an actual event handler that would allow you to use async/await correctly.
protected override void OnAppearing() {
this.Appearing += Page_Appearing;
base.OnAppearing();
}
private async void Page_Appearing(object sender, EventArgs e) {
//...call async code here
await DataBaseService.checkNoteAlarmTimeActive();
var notes = await loadNotes();
listNotes.ItemsSource = notes;
//unsubscribing from the event (optional but advised)
this.Appearing -= Page_Appearing;
}
/// <summary>
/// Generate list of notes basic on current sorting option and active switcher
/// </summary>
private Task<IEnumerable<Note>> loadNotes()
{
return _sorting.sortNotes(_sortOption, _activeSwitcherState);
}
I would probably guess that this piece of code...
if (noteid != 0)
{
this.loadNoteView(noteid);
}
called in the constructor should be refactored out into the event handler as well.

Xamarin portable, how to navigate back from selected list item to MainPage and pass value

My previous question was, how to navigate from ToolbarItem to another page and keep navigation bar existing. : Xamarin portable project navigate with ToolbarItem to another page by using MasterDetailPage
Now I have troubles when I select item from item list and I want to back to my MainPage, but I am getting such a error: System.Exception: Android only allows one navigation page on screen at a time and MainPage page appear, but it freeze and I see now 2 buttons on navigation bar. But it should be only one.Here in MainPage I am calling Cities:
public partial class MainPage : MasterDetailPage
{ public MainPage()
{
InitializeComponent();
masterPage.ListView.ItemSelected += OnItemSelected;
CityClick.Clicked += async (sender, e) =>
{
await Detail.Navigation.PushAsync(new Cities());
};}}
Then when I am at Cities.xaml.cs I want to back to MainPage(). And also I want pass my selected item value from list to my label in MainPage.xaml navigation. Second problem is when I am returning from Cities.xaml.cs after item select to MainPage() I am getting that error which I mentioned before. This is my Cities class:
public partial class Cities : ContentPage
{
public Cities()
{
InitializeComponent();
Label header = new Label
{
Text = ...
};
List<City> cities = new List<City>
{new City("City1"),
new City("City2")};
ListView listView = new ListView
{ItemsSource = cities,
ItemTemplate = new DataTemplate(() =>
{
Label nameLabel = new Label();
nameLabel.SetBinding(Label.TextProperty, "Name");
BoxView boxView = new BoxView();
return new ViewCell
{
...
};
...
{
Children =
{
...
}
};
listView.ItemSelected += async (sender, e) =>
{
if (e.SelectedItem == null)
{return;}
else
{
await Navigation.PushAsync(new MainPage());
}
};
}
class City
{public City(string name)
{
this.Name = name;
}
public string Name { private set; get; }
};}
And this is how looks when returns to MainPage() it freeze everything and appear another label:
EDIT : Regarding #AkashAmin comments I changed from await Navigation.PushAsync(new MainPage()); to await Navigation.PopAsync(); and it is worked very well. Now I still have dilemma with pasiing value from City class to MainPage class.
I navigated back from my Cities class to my MainPage by changing from PushAsync to PopAsync(); . Thank you #Akash Amin for your information. This awaited task also solved duplicated labels problem in Navigation ToolbarItems place .
Also I solved value passing from Cities to MainPage class problem. In this link you can see my all walkthrough of solving this problem: https://stackoverflow.com/a/37350738/3727758

Categories

Resources