Closed GuidoNeele closed 11 months ago
@brminnick it only took 14 days for someone to request this 😂
https://github.com/CommunityToolkit/Maui/pull/1165#pullrequestreview-1709172039
Hi @GuidoNeele! The good news is that you're experiencing the expected behavior; PopupService
does not assign a Popup's BindingContext
.
Looking at the PR you've submitted, you are assigning the Popup.BindingContext
in ShowPopup()
. I strongly disagree that ShowPopup()
should do anything other than display the Popup
on the screen; it shouldn't be modifying any of the properties inside Popup
. For this reason, I've added the https://github.com/CommunityToolkit/Maui/labels/do%20not%20merge label to the PR for now.
When using ShowPopup(new ViewModel()) I expect the passed instance of ViewModel to be assigned to the BindingContext of the newly created popup.
Can you help me understand your expectation? Is it written in our documentation that PopupService
assigns / overwrites Popup.BindingContext
? Is there an example from a Dependency Injection library (eg Microsoft.Extensions.DependencyInjection
) where it assigns property values when adding files to IServiceProvider
? We could use leverage an existing implementation if one exists.
I strongly feel that it is out-of-scope for PopupService
to overwrite the value of any properties in your Popup
class.
That being said, I'm happy to be proven wrong. If there are existing examples where a Dependency Injection library has similar behavior, please do share them.
I'm sorry Brandon, but I feel your comment is a bit strange and trying to send me into the woods. It's clear by Shawn's previous comment that you already internally have discussed this or something like it. I somewhat understand what your stance is but I don't see any problem with the issue I opened or the pull request I proposed.
The main problem here is that the PopupService is exposing 2 methods which require newing up an instance of a view model. They are not asking for a Type, they are asking for an object. The question is how can I not expect that object to be attached to the popups BindingContext? Why else would I create that object?
I'm sorry Brandon, but I feel your comment is a bit strange and trying to send me into the woods. It's clear by Shawn's previous comment that you already internally have discussed this or something like it. I somewhat understand what your stance is but I don't see any problem with the issue I opened or the pull request I proposed.
Yes, we did have a previous conversation, and I'm looking for more examples and evidence. The implementation in your PR breaks the Single Responsibility principle of ShowPopup()
. We cannot move forward with that implementation. Additional examples + evidence will help us shape this conversation and a possible implementation.
The main problem here is that the PopupService is exposing 2 methods which require newing up an instance of a view model. They are not asking for a Type, they are asking for an object. The question is how can I not expect that object to be attached to the popups BindingContext? Why else would I create that object?
Quick correction - they don't require newing up an instance of a view model. You should only be using IPopupService.ShowPopup<TViewModel>(TViewModel viewModel);
when you have access to the ViewModel instantiated by the IServiceCollection
(ie only use is when the ViewModel is injected into the class via dependency injection).
Looking at your sample code, you are using the incorrect PopupService
API. I've submitted a PR that demonstrates that you should be using IPopupService.ShowPopup<MyViewModel>()
in your ContentPage: https://github.com/GuidoNeele/mct_popupservice_issue/pull/1
I've annotated the code in my PR to help explain the differences between the two PopupService
APIs.
Is adding an IoC-style factory function for a popup configuration - also no-go?
Like this:
Task<object?> ShowPopupAsync<TViewModel>(Action<Popup, TViewModel> configure,
CancellationToken token = default(CancellationToken)) where TViewModel : INotifyPropertyChanged;
I just thought the reason I am asking is not clear...
When you run ShowPopupAsync() via IPopupService, you don't have access to the instance of the Popup. As such, you are crippled because you can't show popups that have to be closed by the caller. Use case: some background task wants to kill 'loading' popup spinner when its, in fact, done loading. No, adding 'All done please press one more button' is not a good UI.
Example of the code that doesn't work
static public async Task<LoadingPopupViewModel> CreateAndShow(string htmlText)
{
LoadingPopupViewModel model = null;
await MainThread.InvokeOnMainThreadAsync(() =>
{
var popupService = IoC.Services.GetRequiredService<IPopupService>();
//cannot block! We need a background task to complete before we close it!
_ = popupService.ShowPopupAsync<LoadingPopupViewModel>(
onPresenting: (m) =>
{
m.HtmlText = "Custom loading cue";
//when is this going to happen? No idea.
model = m;
});
});
return model; //will return NULL because the lambda above wasn't executed yet!
}
I just thought the reason I am asking is not clear...
When you run ShowPopupAsync() via IPopupService, you don't have access to the instance of the Popup. As such, you are crippled because you can't show popups that have to be closed by the caller. Use case: some background task wants to kill 'loading' popup spinner when its, in fact, done loading. No, adding 'All done please press one more button' is not a good UI.
You aren't crippled, we just haven't made that part any easier for you yet. You can follow this approach which fires an event:
Note the above example also shows how to assign the BindingContext which I have seen you ask somewhere.
For the ability to close a Popup from the caller, we do have a PR open for that and are just working through testing it. This it the PR https://github.com/CommunityToolkit/Maui/pull/1688
Is there an existing issue for this?
Did you read the "Reporting a bug" section on Contributing file?
Current Behavior
The viewmodel in this snippet of code is not assigned to the popup which you would expect if you create the viewmodel yourself.
https://github.com/CommunityToolkit/Maui/blob/d00c4a077f7f04e4a9596e96232b6ee7f46d73dd/src/CommunityToolkit.Maui/PopupService.cs#L59-L68
Expected Behavior
When using ShowPopup(new ViewModel()) I expect the passed instance of ViewModel to be assigned to the BindingContext of the newly created popup.
Steps To Reproduce
PopupService.AddTransientPopup<MyPopup, MyViewModel>(services);
Link to public reproduction project repository
https://github.com/GuidoNeele/mct_popupservice_issue
Environment
Anything else?
No response