3
votes

I'm looking for a good way to implement a truly modal dialog in Silverlight 5. Every example that I find that claims to create a modal dialog really isn't modal in that the calling code waits until the dialog is closed.

I realize this is a challenge because we can't actually block the UI thread because it must be running in order for the dialog (ChildWindow) to function correctly. But, with the addition of the TPL in SL5 and the higher level of adoption Silverlight has seen over the past few years, I'm hoping someone has found a way around this.

A good representative scenario I am trying to solve is an action (say clicking a button or menu item) that displays a login dialog and must wait for the login to complete before proceeding.

Our specific business case (whether logical or not) is that the application does not require user authentication; however, certain functions require "Manager" access. When the function is accessed (via button click or menu item selected, etc), and the current user is not a manager, we display the login dialog. When the dialog closes, we check the user's authorization again. If they are not authorized, we display a nice message and reject the action. If they are authorized, we continue to perform the action which typically involves changing the current view to something new where the user can do whatever it is they requested.

1
A typical workaround is a static (e.g. your dialog) method call that takes functions as parameters. You define what happens when you succeed vs fail using two inline anonymous functions in the call. The rest of your code is event driven, so you should try to work with the async model and not against it. :)Gone Coding
In my case, we 're-implemented' modal by having a subview that is not a ChildWindow along with a semi-opaque view that prevents inputs to reaching the blocked elements. The visibility of the 'modal' system is data bound.jv42

1 Answers

5
votes

For the sake of closure...

What I ended up with is a new TPL-enabled DialogService with methods like:

public Task<Boolean?> ShowDialog<T>()
    where T : IModalWindow

The method creates an instance of the dialog (ChildWindow), attaches a handler to the Closed event and calls the Show method. Internally, it uses a TaskCompletionSource<Boolean?> to return a Task to the caller. In the Closed event handler, the DialogResult is passed to the TrySetResult() method of the TaskCompletionSource.

This lets me display the dialog in a typical async way:

DialogService.ShowDialog<LoginDialog>().ContinueWith(task =>
{
    var result = task.Result;

    if ((result == true) && UserHasPermission())
    {
        // Continue with operation
    }
    else
    {
        // Display unauthorized message
    }
}, TaskScheduler.FromCurrentSynchronizationContext());

Or, I could block using the Task.Wait() method - although this is problematic because, as I mentioned in the original post, it blocks the UI thread, so even the dialog is frozen.

Still not a true modal dialog, but a little bit closer to the behavior I am looking for. Any improvements or suggestions are still appreciated.