Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xamarin form MessagingCenter Unsubscribe is not working as expected

Functionality written inside the MessagingCenter.Subscribe() is called multiple times when i navigate to and fro multiple times in the application. But each time before subscribing, i do unsubscribe to the same in constructor as follows, still it didn't worked.

MessagingCenter.Unsubscribe<SubmitPage>(this,"Save");
MessagingCenter.Subscribe<SubmitPage>(this, "Save", (sender) =>
{
   DisplayToastOnSuccessfulSubmission();
});

In my application i have 6 pages(git) and i save the data in 6th page with MessagingCenter.Send and same will be subscribed in 2nd page and saved message will be displayed in 2nd page(after navigating to that page).

Now i navigate like 2->1->2->3->4->5->6 in this particular case DisplayToastOnSuccessfulSubmission() would be called two times(because Page2 constructor is called twice).

I even tried placing the same code in OnAppearing. I can't unsubscribe in OnDisappear as I need the event wiring up to when I reach Page6 for save.

Reproduced the same behaviour in sample project and added here https://github.com/suchithm/MessageCenterSampleApp
Drop box link

What is the proper way to do this?

like image 412
Suchith Avatar asked Jun 23 '17 11:06

Suchith


3 Answers

I faced same issue. I solved issue by passing the same parameters inn subscribe and unsubscribing as well.

MessagingCenter.Subscribe<Page1, T>(this, "Listen", async (Page1 arg1, T 
listenedString) =>
{

});

Unsubscribe like below

 MessagingCenter.Unsubscribe<Page1, T>(this, "Listen");
like image 132
kalyan Avatar answered Nov 06 '22 21:11

kalyan


But each time before subscribing, I do unsubscribe to the same in constructor as follows, still it didn't worked.

MessagingCenter.Subscribe() is called multiple times, because there are two instances of Page2 in your code, both of them use MessagingCenter.Subscribe() method, that's why the Unsubscribe didn't work.

You can modify page2() to a singleton to make sure there is only one instance of Page2 in your project, after that when you send a message, the MessagingCenter.Subscribe() is called only once.

Page2.cs:

public static Page2 instance = new Page2();

public static Page2 GetPage2Instance()
{
    if(instance == null)
    {
        return new Page2();
    }
    return instance;
}

private Page2()
{
    InitializeComponent();
    MessagingCenter.Unsubscribe<Page2>(this, "SaveToastPage2");
    MessagingCenter.Subscribe<Page2>(this, "SaveToastPage2", (sender) =>
    {
       DisplayToastOnSuccessfulSubmission();
    }
 }

When you send a message :

MessagingCenter.Send(Page2.GetPage2Instance(), "SaveToastPage2");

EDIT :

Remember that declaring constructors of Page2 class to be private to make sure there is only one instance of Page2 in your project sure.

private Page2()
{
   ...
}

Modify your Page1.cs code :

async void Handle_Next(object sender, System.EventArgs e)
{
    await App.NavigationRef.PushAsync(Page2.GetPage2Instance(), true);
}
like image 28
York Shen Avatar answered Nov 06 '22 20:11

York Shen


I'm using this temporary solution. I declared a static dictionary to storage my object (to this example I used an object type).

private static Dictionary<string, object> subscribedReferencePages = new Dictionary<string, object>();

And I always storage the last subscribed page reference. Then I compare the page reference before triggering the message method to fire only the last one.

    subscribedReferencePages[pageName] = this;
    MessagingCenter.Subscribe<ViewModelBase>(this, pageName, async (sender) =>
    {
        if (!ReferenceEquals(sender, this))
        {
            return;
        }

        this.OnInitialized();
    });

To call the message method I need to pass the dictionary as parameter (instead of the "this" reference).

 MessagingCenter.Send(subscribedPages[pageName], keyPageName);
like image 1
FabioSSena Avatar answered Nov 06 '22 21:11

FabioSSena