Maui icon indicating copy to clipboard operation
Maui copied to clipboard

[BUG] ViewModel that gets passed to PopupService gets ignored

Open Mysame opened this issue 1 year ago • 3 comments

Is there an existing issue for this?

  • [X] I have searched the existing issues

Did you read the "Reporting a bug" section on Contributing file?

  • [X] I have read the "Reporting a bug" section on Contributing file: https://github.com/CommunityToolkit/Maui/blob/main/CONTRIBUTING.md#reporting-a-bug

Current Behavior

Popupservice allows you to pass an existing ViewModel, and it will get the correct popup. It does get the correct popup, but the viewmodel you pass through gets ignored, a new (empty) one gets made that makes it into the popup.

https://github.com/CommunityToolkit/Maui/blob/819ab10a3a53c76e514410e8ee0af2c5c7a6fe9c/src/CommunityToolkit.Maui/PopupService.cs#L115-L124 The variable doesn't seem to be getting used.

Expected Behavior

ViewModel should be passed to the Popup instance and be the current active BindingContext

Steps To Reproduce

Implement the PopupService according to https://learn.microsoft.com/en-us/dotnet/communitytoolkit/maui/views/popup Then try the overload where you can pass your existing ViewModel to create a Popup.

I've added a link to an example repro that implements the popups in the same way I did, except it doesn't use the overload anywhere.

Link to public reproduction project repository

https://github.com/jfversluis/MauiToolkitPopupSample

Environment

- .NET MAUI CommunityToolkit: 9.0.1
- OS: Android 34
- .NET MAUI: 8.0.60

Anything else?

I hope this fixes my popups not scaling to content. Knock on wood.

Mysame avatar Jun 25 '24 19:06 Mysame

Why do you need to use this overload instead of the onPresenting overload? The functionality that you are after was removed before the popup service got merged and there is a current expectation that we will remove the method entirely

bijington avatar Jun 25 '24 19:06 bijington

Because we're already managing our ViewModel. I can start syncing variables in the onPresenting on the newly created one, but that's less than ideal. The overload seemed plenty, and well fit for our need. I used it because it was there.

Mysame avatar Jun 25 '24 20:06 Mysame

Yeah I get that and you are not the first to ask this. Also I've noticed that our XML docs state the behaviour you are expecting should be the case. Let me see what the rest of the team think

bijington avatar Jun 25 '24 20:06 bijington

Maybe I am not understanding the issue. This worked for me: var vm = new LocationViewModel(_locationdatastore); await vm.Refresh(); var popup = new PopupLocationsView(vm); var result = await Shell.Current.ShowPopupAsync(popup, CancellationToken.None);

davefxy avatar Jul 11 '24 16:07 davefxy

Maybe I am not understanding the issue. This worked for me: var vm = new LocationViewModel(_locationdatastore); await vm.Refresh(); var popup = new PopupLocationsView(vm); var result = await Shell.Current.ShowPopupAsync(popup, CancellationToken.None);

~~The code won't error and a popup will show, however anything you filled into the viewmodel will be ignored, as your vm instance isn't the one used in the actual popup~~

See response below, the code in quoted post is different code than discussed in initial ticket.

Mysame avatar Jul 11 '24 17:07 Mysame

The vm did work. My popup is using binding to an ObservableCollection in the vm. Everything is displayed as defined in the vm. It works great. I use this popup to permit the user to delete entries stored in a database.

davefxy avatar Jul 11 '24 18:07 davefxy

Oh, I'm sorry, I see where I went wrong in my response. This ticket relates to the CommunityToolkit.Maui.Core.PopupService class. https://learn.microsoft.com/en-us/dotnet/communitytoolkit/maui/views/popup#displaying-popups Specifically, its exposed method ShowPopupAsync() as linked in the main post.

The Shell method works fine because you create your own view, whereas the PopupService handles this itself.

Mysame avatar Jul 11 '24 19:07 Mysame

Facing the same issue on my side! From what I'm seeing so far, the easiest fix would be to create another GetPopup method taking the ViewModel as a parameter and setting it as BindingContext like so:

Popup GetPopup<TViewModel>(
	TViewModel viewModel)
{
	var popup = GetPopup(
		typeof(TViewModel));
		
	popup.BindingContext = viewModel;


	return popup;
}

In the ShowPopup methods that request a ViewModel as parameter, it would then be necessary to call this new GetPopup method.

Pantheas avatar Oct 10 '24 21:10 Pantheas

We will be deprecating the public void ShowPopup<TViewModel>(TViewModel) API. It will be marked [Obsolete] in the next release.

I understand the desire, and we've discussed the pros + cons of this in the past in our monthly standups.

However, it's wrong for an API called ShowPopup to do any hidden variable assignment under the hood that the caller may be unaware of. It is also a breaking change because it breaks existing functionality for folks currently using the API as designed.

The recommended way to use PopupService is to add both the Popup and its ViewModel to builder.Services using PopupService.AddTransient in MauiProgram.cs, then call PopupService.ShowPopup<TViewModel>().

TheCodeTraveler avatar Oct 15 '24 18:10 TheCodeTraveler