I am new to C# and Xamarin Forms and am trying to implement Messaging Center in my project. I am trying to push a modal page and then send data from the modal back to the original page. However, it isn't quite working as I expected.
Here is the code from the main page:
MessagingCenter.Subscribe<Info, string[]>(this, "nameUpdate", (sender2, name) =>
{
dataName.Text = name[0];
});
await Navigation.PushModalAsync(new Info(dataName.Text));
MessagingCenter.Unsubscribe<Info, string[]>(this, "nameUpdate");
And here is the code to execute when a button is pressed on the modal page, where message is a string[]:
await Navigation.PopModalAsync();
MessagingCenter.Send<Info, string[]>(this, "nameUpdate", message);
MyPage is the name of the original page, and Info is the name of the page that is being called as a modal. I am not getting any errors, just the statements in the subscribe block are not executing.
Thank you in advance.
Try to remove unsubscribe and swap the order of these two:
await Navigation.PopModalAsync();
MessagingCenter.Send<Info, string[]>(this, "nameUpdate", message);
It seems the unsubscribe happens before the send.
Related
I have a Xamarin project. When I run in UWP OnAppearing initially fires once and then loads the Login Page. After successfully logging in, my Main page fires OnAppearing again and I load data into my ViewModel.
However, if I run the project in Android, OnAppearing only fires once - When the Main page initially loads.
protected override async void OnAppearing()
{
if (!App.IsUserLoggedIn)
{
await App.NavigationService.NavigateModalAsync(PageNames.LoginPage, false);
}
else
{
((SchedulerViewModel)Schedule.BindingContext).LoadData();
}
base.OnAppearing();
}
Why does Android only fire once? Or is UWP the one misbehaving?
NOTE: NavigationService is not a standard Xamarin Forms class. I assume it is built on top of Page.Navigation.PushModalAsync and PopModalAsync.
This is documented behavior of Modal Stack on Android:
Popping Pages from the Modal Stack:
When PopModalAsync is invoked, the following events occur:
...
The page being returned to has its OnAppearing override invoked, provided that the underlying platform isn't Android.
NOTE: it seems to depend on the API version of Android. I just tested it on API 30, and Android did fire OnAppearing again, when modal page was popped.
Instead of code in OnAppearing, I would solve it like this:
In App.xaml.cs, instead of:
MainPage = new MainPage();
do:
if (!App.IsUserLoggedIn)
MainPage = new LoginPage();
else
MainPage = new MainPage();
Then when LoginPage is done, instead of pop modal, do:
Application.Current.MainPage = new MainPage();
NOTE: Adapt as needed, if these are pages inside NavigationPage or AppShell.
I have xamrin.forms project with both Android and iOS. I have just simple 2 pages where i call one from the other. On android everything is working perfectly as it should but on iOS any call for forms (navigation.PushAsync, DisplayAlert, ...) is not working properly (does nothing) until I put application to the sleep (put it to the background ) and then when I reload it back everything starts to work perfectly.
This is how i create first page in App.xaml.cs
var page = new NavigationPage(new FirstPage());
MainPage = page;
Button command for my first page calls for this:
FormsNavigation.PushAsync(secondPage, true);
I allredy tried to wrap Push into Device.BeginInvokeOnMainThread but no result.
In Xamarin.Forms, when using a NavigationPage to navigate to a ContentPage, use await Navigation.PushAsync.
And, because all UI animations must be invoked on the Main UI Thread, I recommend wrapping it Device.InvokeOnMainThreadAsync.
async Task NavigateToSecondPage()
{
var secondPage = new SecondPage();
await Device.InvokeOnMainThreadAsync(() => Navigation.PushAsync(secondPage, true));
}
On my Xamarin.Forms app I using a three different types of Buttons. These are their on click functionalities:
Navigation Buttons:
I use them to navigate to an other page if I will need to came back later to the previous page.
btn_navigate.Clicked += (sender,e) => {
Navigation.PushAsync(new Page());
};
Error: If the new page takes a few seconds to load, doing a quick multi click on these buttons open several pages.
Non returnable navigation Buttons:
I use them to navigate to an other page when I want to avoid the user came back to the previous page. I destroy the current page after I insert before my new page.
btn_non_returnable_navigate.Clicked += (sender,e) => {
Navigation.InsertPageBefore(new Page(), this);
Navigation.PopAsync();
};
Error: If the new page takes a few seconds to load, doing a quick multi click on these buttons throws an exception: Before must be in the pushed stack of the current context. This is because the first click create the new page and destroy the current one, the second click cant not destroy to the current page because it is already destroyed so it throws the exception.
HTTP request Buttons:
I use them to send a HTTP request to the server. Usually after the HTTP request was completed it navigate to an other page. Those are obviously the more important ones.
btn_http_request.Clicked += (sender,e) => {
Uri uri = new Uri("http://192.168.0.1:8080/request");
HttpClient client = new HttpClient();
HttpResponseMessage http_response = client.GetAsync(uri);
....
Navigation.InsertPageBefore(new Page(), this);
Navigation.PopAsync();
};
Error: If the request takes a few seconds to get the answer, doing a quick multi click on these buttons throws several HTTP request. It should not happen.
All of these buttons are combined on the same page multiple times. So if the user try to click multiple buttons repeatedly he will tear down the app.
These issues are caused because the asynchronously of the button actions. But I think it will be solve by using a locker for these buttons so they could only clicked once a time.
Have Buttons some property like this? If it is not, how could I create a Buttons extension that fix this problems? I would like to have as simple solution as it possible. I need to control this issue in a lots of Buttons and if it is a complicated solutions it may do a tricky code problem.
On WPF this code works as I need but on Xamarin there is not RoutedEventArgs:
C# Button extension
public partial class ButtonEx : Button{
public bool Active;
public ButtonEx(){
InitializeComponent();
Active = true;
}
private void Extension_Click(object sender, RoutedEventArgs e){
if (Active) {
Active = false;
} else {
e.Handled = true;
}
}
}
XAML Button extension
<Button x:Class="test.ButtonEx"
..
Click="Extension_Click">
</Button>
C# on the code
...
ButtonEx buttonEx = new ButtonEx()
//Click function of the button
buttonEx.Click += (sender, e) =>{
//This code only happen if buttonEx.active = true
...
(sender as Button).Active = true;
}
...
When you click the extended button it throws two events. The fist one, the Extension_Click and the second one the Click function of the button. The second event only happen when the buttonEx.active = true. The first even allows or blocks the second.
It is there an alternative like this to Xamarin.Formns?
Thank you
The best practice for this including on WPF is to make the button disabled while it performs some action and shouldn't/can't perform additional actions. That is by the book. Technically someone can make a new sort of button that would perform this automatically. I would guess that the fact that no one made it by now is that this is not worth the effort / brings at least as much troubles as it resolves. Unfortunately I would guess that if you need something like that you will have to make it yourself, but it is definitely possible.
I am trying to simply show a label that shows a user that the application is processing some data. The break down of what I am trying to do:
User clicks button
Label displays saying "Loading data..."
Execute Method
Await the Method
Label from step 2 should now display "Done Upload!"
I was able to accomplish all except step 2. My code does not display the "Loading data..." prior to executing the method - it simply runs the methods and displays "Done Upload!" after the execution.
I was hoping to figure out why my code is not executing step 2 and how I can change my code to show the initial "Loading data..." in my label.
Please and thank you!
Here is my button click:
protected async void Sync_Click(object sender, EventArgs e)
{
lblProgress.Text = "Loading data...";
Task<String> task = new Task<string>(SyncPath);
task.Start();
String result = await task;
lblProgress.Text = result;
}
Here is my method:
private String SyncPath()
{
// do heavy stuff
return "Done Upload!";
}
I expect the user to see the initial "Loading data..." text in the label and then code execution followed by "Done Upload" in the aforementioned label. However, the user does not see the initial "Loading data..." but only see the "Done Upload" after the code execution.
Your problem is that the page will not be updated until it has been reloaded. Sync_Click is working as you intend but it runs on the server and the page will not be updated because it runs on the client.
You need to have an ajax update panel and the label should go inside it. Then you can update the label text without reloading the entire page.
I have a Xamarin Forms application, which has 2 buttons on the toolbar. Currently I'm using FreshMVVM (and it's navigation). I want to load pages without putting them into the navigation. I do not want to have the 'back' button on the toolbar, also I do not want the user return the last page.
Here's how I push a page currently:
CoreMethods.PushPageModel<FirstChoicePageModel>();
I tried to push as a modal, but that way the toolbar buttons does not work until I press back. Should I make new navigation containers and switch to them if I push the buttons?
It's been a little while since I've used FreshMVVM, but if I recall correctly, you have 2 options:
If you want to completly reset the nav stack, you can do CoreMethods.PushPageModelWithNewNavigation<FirstChoicePageModel>();
If you want to keep the nav stack, you can set NavigationPage.SetHasBackButton(this, false); in the code behind of the view.
For both of these options, it may necessary to intercept the back button on Android. In the code behind there is an overrideable method:
protected override bool OnBackButtonPressed()
{
return true; // prevent Xamarin.Forms from processing back button
}
If you want to show a page, but you doesn't want to navigate (change the current page), you can always use Popups.
See this link https://github.com/rotorgames/Rg.Plugins.Popup