I suggest to use Xamarin Community Toolkit for this scenario.
Take a look to watch
Nested subscription to messages on xamarin forms
Hello,
I'm new with Xamarin forms and don't know how to deal with this case. I've tryed to implement it in several ways but with no success.
I have a page where when user performs an action (write a text on a text box and send it with enter key) my app must make some checkings.
Depending on the result of the checks, it could be necessary to show a modal page with a list of item to select. Ones user makes the selection, process must continue with other checks. And here is my problem, because in this next checkings I need to show another page to make another selection and then continue to complete the proccess, but this page is not appear. I'm using the MessagingCenter to subscribe to the modal pages. First modal page appears and makes the selection well. Second modal page is never shown and then proccess never complets. Here is some of my code:
NavigationPage navigationPage = new NavigationPage(new ListItemsPage(products));
Navigation.PushModalAsync(navigationPage);
MessagingCenter.Subscribe<ListItemsPage, Guid?>(this, "Select product", (obj, item) =>
{
try
{
if (item != null)
{
product = products.SingleOrDefault(x => x.Guid == item);
if (product != null) ProcessLine(product);
}
}
catch(Exception ex)
{
throw ex;
}
finally
{
MessagingCenter.Unsubscribe<ListItemsPage, Guid?>(this, "Select product");
}
});
On ListItemsPage I have this code whe item is selected:
private void MenuItem_Clicked(object sender, EventArgs e)
{
// some logic...
Navigation.PopModalAsync();
MessagingCenter.Send(this, "Select product", SelectedGuid);
}
SelectedGuid is a Guid type data and when debbugin is well selected. Problems comes when goes to ProcessLine method.
private void ProcessLine(Product product) {
// make some logic...
NavigationPage navigationPage = new NavigationPage(new ControlUnitsPage(model));
Navigation.PushModalAsync(navigationPage);
MessagingCenter.Subscribe<ControlUnitsPage, ControlUnits>(this, "Select units, date and lot code", (obj, item) =>
{
try
{
if (item != null)
{
_date = item.Date;
_code = item.Code;
_units = item.Units;
Save(productLine, product, _units, _date,_code);
}
}
catch(Exception ex)
{
throw ex;
}
finally
{
MessagingCenter.Unsubscribe<ControlUnitsPage, ControlUnits>(this, "Select units, date and lot code");
}
});
}
ControlUnitsPage has the same structure as the last one page. First makes a PopModalAsync and then sends the message sending an instance of ControlUnits type.
private void Button_Clicked(object sender, EventArgs e)
{
//some logic...
Item = new ControlUnits() { Date = DateField.Date, Code = CodeField.Text, Units = int.Parse(SelectedUnits.Value.ToString()) };
Navigation.PopModalAsync();
MessagingCenter.Send(this, "Select units, date and lot code", Item);
}
I think problem is in the order of invoking method but dont know what is the properly order because I am not able to understand how pushmodal, popmodal methods works, whether or not I should use await with it if after that comes a subscription. I really don't know and I need help, please.
Thank you so much!
4 answers
Sort by: Most helpful
-
Alessandro Caliaro 4,181 Reputation points
2021-06-14T11:45:28.507+00:00 -
Kyle Wang 5,531 Reputation points
2021-06-15T05:32:59.487+00:00 Hi hella-2473,
Welcome to our Microsoft Q&A platform!
I tested the code and it works fine. When you call Send, you should make sure that it is consistent with the parameter type in the Subscribe. So the "SelectedGuid" should also be type of
Grid?
. Try to add breakpoint on the corresponding line to check whether it is executed.It seems that you just want to pass some parameters to method "Save". You can completely implement it through a custom constructor, similar to
new ListItemsPage(products)
.In general, it is not recommended to use MessageCenter, only when there is no any connection between the two pages you can choose to use it.
Update
ListItemsPage.xaml.csList<Product> Products { get; set; } public ListItemsPage(List<Product> products) { InitializeComponent(); Products = products; } private void MenuItem_Clicked(object sender, EventArgs e) { Navigation.PopModalAsync(); // SelectedGuid for test Guid? SelectedGuid = Products[0].Guid; Product product = Products.SingleOrDefault(x => x.Guid == SelectedGuid); if (product != null) { Navigation.PushModalAsync(new ControlUnitsPage(product)); } }
ControlUnitsPage.xaml.cs
public Product TheProduct { get; set; } public ControlUnitsPage(Product product) { InitializeComponent(); TheProduct = product; } private void Button_Clicked(object sender, EventArgs e) { ControlUnits item = new ControlUnits() { Date = DateTime.Now, Code = "abc", Units = 1}; // Call Save // don't know what productLine here is Save(productLine, TheProduct, item.Units, item.Date, item.Code); Navigation.PopModalAsync(); }
Regards,
Kyle
If the response is helpful, please click "Accept Answer" and upvote it.
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.
-
Harrison of The North 196 Reputation points
2021-06-15T11:48:44.973+00:00 Hi @hella
Having looked at the other responses, I thought I'd just add a penny's worth!
When invoking a modal page from another page in a pattern where dismissing the modal page will return to the original page - which will be updated from the previous actions in the modal page - it's a good idea to create a service (singleton) that just before you call the modal page, you add whatever data you need to the service, then open the modal page, which in it's OnAppearing method calls that service, then, during that page's user activity, you add whatever info that you want returning to the original page to that service, so that when you dismiss the modal page, the original page's OnAppearing method is called, in which you use the new info in the same service to update the original page. Then, as you continue to edit and then have to open a modal page again, the same cycle continues.
There are, of course, many patterns that you could use, and I see that you are using the MessagingService - perhaps you'd be better off not using it for this (I never use it, instead relying on services) and instead use a service.
-
Harrison of The North 196 Reputation points
2021-06-16T09:04:47.48+00:00 Essentially, you want to put data into a service before opening the modal page, then retrieving the same data from the same service in the OnAppearing event in the Modal page, when it opens. The pattern is the same when dismissing the Modal page, you put data in the service just before you dismiss the page, and collect it in the original page's OnAppearing event. So rewally, this is just a matter of how to write a service that maintains state from wherever you access it.
There are basically two patterns that are popular for this, one is merely creating a singleton class, which as a static class, you can access from anywhere. A singleton is typically accessed from anywhere using the syntax
var functionReturnResult = MyClass.Default.MyMethod(somevariable1, etc);
however much more popular is using some sort of dependence injection framework, such as MvvmLight, which you should aim to be a specialist at.
For MvvmLight or any other DI frameworks just Youtube them.