简体   繁体   中英

MVVM multiple Dialogs headache

I am using caliburn micro. My problem is how to manage dialogs. The biggest problem is that because when not using window your code doesnt stop and wait.

So i did something like this.

public void ShowDialog(IScreen dialogModel, Action<object> callback = null)
{
    ActivateItem(dialogModel);

    if (callback != null)
        dialogModel.Deactivated += delegate { callback(dialogModel); };

}

This has lots of problem.For example in case i want to show dialog A and then at callback i want to show dialog B under certain cases there comes a problem.I have to write an extra function for DoSomething in order not to duplicate.And i loose all the other local variables..The problem is bigger when more levels are required..

    showDialog(A, (cb)=>{

    if(...) {

    showDialog(B,(cb2)=>{
       DoSomething();

    });

    }
    else{
    DoSomething();
    }
});

Also because i wanted to show one dialog at a time i extended Collection.OneActive . But this had problem too. In deactivate event callback i couldnt close all if i wanted to! Because it keeps in memory the next reference after Deactivated is triggered and even if you clear it it comes again..

How about using a class to track state information as you move between dialogs, rather than nesting closures as shown in your original example?

I think you're on the right track, but it seems like you have two problems:

  1. The amount of nesting that you're doing is not good for code clarity.
  2. You need a better way to capture local variables and state information between dialogs.

To solve the first problem, I'd recommend breaking apart your logic into different methods. Every time a dialog is deactivated, you could have a method to handle the logic that should be executed afterward.

To solve the second problem, you might try creating a class that is responsible for storing the information that you want to pass between dialogs. An instance of this class could be passed in as an argument into each method that is to be executed upon dialog deactivation.

Here's how you could accomplish this:

Conductor Class

public class DialogTestsViewModel : Conductor<object>.Collection.OneActive
{
    /// <summary>
    /// Shows a dialog and executes its callback if necessary.
    /// </summary>
    /// <param name="dialogModel">The dialog view model to be shown.</param>
    /// <param name="callback">The callback to be executed when dialog is closed.</param>
    public void ShowDialog(IScreen dialogModel, Action callback = null)
    {
        // Show the dialog.
        ActivateItem(dialogModel);

        // If there is a callback, call it when dialog is closed / deactivated.
        if (callback == null) return;
        dialogModel.Deactivated += (sender, args) => callback();
    }

    /// <summary>
    /// This method kicks off the dialog chain.
    /// </summary>
    public void ShowFirstDialog()
    {
        // Create a new context. This will hold state information
        // as it is passed between dialogs.
        var context = new TestDialogContext();

        // Create the first dialog's view model.
        var viewModel = new FirstDialogViewModel();

        // Show the first dialog.
        ShowDialog(viewModel, () => OnFirstDialogDeactivated(viewModel, context));
    }

    /// <summary>
    /// Logic to be executed when the first dialog is closed.
    /// </summary>
    /// <param name="viewModel">The first dialog's view model.</param>
    /// <param name="context">The state information.</param>
    private void OnFirstDialogDeactivated(FirstDialogViewModel viewModel, TestDialogContext context)
    {
        // Check the view model here and store state information inside the context.
        if (viewModel.SomethingIsChecked)
        {
            context.ShouldShowSecondDialog = true;
        }

        // Use information in the view model or the context to decide if we should show the next dialog.
        // You could also make a decision about which dialog to show next here.
        if (context.ShouldShowSecondDialog)
        {
            var secondDialog = new SecondDialogViewModel();
            ShowDialog(secondDialog, () => OnSecondDialogDeactivated(context));
        }
    }

    /// <summary>
    /// Logic to be executed when the second dialog is closed.
    /// </summary>
    /// <param name="context">The state information.</param>
    private void OnSecondDialogDeactivated(TestDialogContext context)
    {
        // Do more stuff.
    }
}

Dialog Context Class

Here is where you would store the state information that needed to be passed between dialogs. I've only included one property here as an example, but you could put a lot of info here.

/// <summary>
/// State information to be passed between dialogs.
/// </summary>
public class TestDialogContext
{
    public bool ShouldShowSecondDialog { get; set; }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM