[Xamarin.Forms] Get returned value from popup from communitytoolkit with mvvm

DiamondKesha 31 Reputation points
2021-09-16T19:00:36.067+00:00

I have a method that opens a Popup with or without a parameter:

    private async Task InternalShowPopupAsync(Type viewModelType, object parameter)
    {
        Xamarin.CommunityToolkit.UI.Views.Popup popup = CreatePopupView(viewModelType);

        App.Current.MainPage.Navigation.ShowPopup(popup);

        await (popup.BindingContext as BaseViewModel).InitializeAsync(parameter);
    }

Can you please tell me how I can now return values from Popup using this method? As I understand it, if I write code dismiss in code-behaind, it will break the mvvm principle. I can use MessagingCenter, but I heard it's better not to use it. What other solutions are there?

Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,294 questions
0 comments No comments
{count} votes

3 answers

Sort by: Most helpful
  1. DiamondKesha 31 Reputation points
    2021-09-18T20:23:45.8+00:00

    Solved the issue with TaskCompletionSource. I hope this solution is better than writing code-behind and using MessagingCenter.
    Example:

    PopupService

    private async Task<object> InternalShowPopupAsync(Type viewModelType, object parameter)
    {
        Xamarin.CommunityToolkit.UI.Views.Popup popup = CreatePopupView(viewModelType); // or just Popup View object
    
        App.Current.MainPage.Navigation.ShowPopup(popup);
    
        var result = await (popup.BindingContext as BaseViewModel).InitializeWithReturnAsync(parameter);
        popup.Dismiss(null);
    
        return result;
    }
    

    Popup ViewModel

     private TaskCompletionSource<object> _taskCompletion;
    
            public override async Task<object> InitializeWithReturnAsync(object parameter = null)
            {
                _taskCompletion = new TaskCompletionSource<object>();
    
                return await _taskCompletion.Task;
            }
    
            public ICommand TestCommand => new Command(() => _taskCompletion.TrySetResult("Value from popup"));
    
    2 people found this answer helpful.
    0 comments No comments

  2. Leon Lu (Shanghai Wicresoft Co,.Ltd.) 68,571 Reputation points Microsoft Vendor
    2021-09-17T02:38:40.17+00:00

    Hello,​

    Welcome to our Microsoft Q&A platform!

    ShowPopupAsync can return a value to the caller

    var result = await Navigation.ShowPopupAsync(popup);

    whatever parameter is passed to Dismiss(backValue) will be returned to the caller.

    Here is my code in ViewModel

       async void PerformShowPopup() {  
         
         
                  // var res=await Navigation.ShowPopup();  
         
                  // Get the value from the popup page  
                   var result = await Navigation.ShowPopupAsync(new Popup01());  
         
                 await  Application.Current.MainPage.DisplayAlert("i",result.ToString(),"OK");  
               }  
    

    Here is my background code of popup page.

       public partial class Popup01 : Popup  
           {  
               public Popup01()  
               {  
                   InitializeComponent();  
               }  
         
               private void Button_Clicked(object sender, EventArgs e) => Dismiss(null);  
         
               
         
               private void Button_Clicked_1(object sender, EventArgs e)  
               {  
                  //return the value  
                   Dismiss(editor_value.Text);  
               }  
           }  
    

    Here is my running screenshot.

    132898-image.png 132952-image.png

    Best Regards,

    Leon Lu


    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.


  3. Trevor Balcom 1 Reputation point
    2022-04-14T16:12:24.27+00:00

    The excellent solution from @DiamondKesha does not handle if the user cancels the popup using the Android back button. If you don't care about that then you could simply disable that functionality by setting IsLightDismissEnabled to false. If you do care then you'll want to override the LightDismiss method in your popup, then set the TaskCompletionSource as cancelled (and catch the OperationCanceledException) or complete depending on your needs.

       protected override void LightDismiss()  
       {  
           ViewModel.PopupResult.TrySetCanceled();  
           base.LightDismiss();  
       }  
    
    0 comments No comments