MahApps / MahApps.Metro

A framework that allows developers to cobble together a better UI for their own WPF applications with minimal effort.
https://mahapps.com
MIT License
9.32k stars 2.45k forks source link

Pattern for returning data from a CustomDialog? #1870

Closed killnine closed 9 years ago

killnine commented 9 years ago

The CustomDialog is a great addition that gives users a lot of flexibility in the content they display. But thinking about the dialogs we have today..

There's still a gap in capability: How can a developer create a dialog in which they are free to return something (not just string) from that dialog?

For instance, I fire off some process that starts, but needs some user input (say, a selection from a ListBox). I don't see a clear way to return this sort of information from any existing dialog. (CustomDialog, while able to display such a selection, immediately returns so it's not useful to this end.)

I'll skip the added complexity of fitting within the confines of MVVM, but has anyone else needed this sort of functionality? If so, where would it go? Into a new dialog? Or fit it within an existing dialog?

llifon commented 9 years ago

A typical approach taken for this from my end is to have a dialog management interface with two methods. Task ShowDialogAsync(IDialogViewModel dialog) and Task HideDialogAsync(IDialogViewModel dialog). Then, when you want a custom return value, you create a new IDialogViewModel implementation that has a method like Task<T> WaitAsync(). In this method I return a TaskCompletionSource whose result is set based on the button that was pressed. If I wanted a view-model with two buttons, one is positive and another is negative, then I'd bind one command the the implementation tcs.TrySetResult(true) and another with tcs.TrySetResult(false).

The call site would look something like this.

TrueFalseDialogViewModel dialog = new TrueFalseDialogViewModel() await IDialogManager.ShowDialogAsync(dialog) bool result = await dialog.WaitAsync() await IDialogManager.HideDialogAsync(dialog)

It means there is a bit of extra work to bind every button each time, but its a very easy approach.

thoemmi commented 9 years ago

I implemented the approach @llifon mentioned in my MVVM library, see https://github.com/thoemmi/TinyLittleMvvm/wiki/Dialogs

killnine commented 9 years ago

@thoemmi: very neat library there, but I'm having trouble implementing it in parallel with MVVMLight. I don't want to rip out MVVML because I think it provides a lot of other good features. DialogManager is an internal class which I can't register via SimpleIoC. Why not open it up?

Other than that, I think it'd be pretty straightforward to use your solution.

More generally speaking, does it make sense to build something like this into the MahApps project itself? I know MA.M tries to stay unopinionated about MVVM or code-behind solutions, but it's a shame there isn't a solution within the base project.

@llifon: Do you have any working source that isn't so dependent on other libraries (Autofac, etc.)?

killnine commented 9 years ago

I have created a test repository that does what I want. It's largely a copy of @thoemmi's implementation, but stripped down a bit more. It also uses MvvmLight (though this particular implementation just creates throwaway instances of the viewmodels via Activator).

https://github.com/killnine/CustomDialogTest

thoemmi commented 9 years ago

@killnine I could remove the dependencies on AutoFac (and NLog) and maybe throw away the Bootstrapper (which relies on Autofac heavily), but then there wouldn't be much left but DialogManager and FlyoutManager :wink: