简体   繁体   中英

Do an action from ViewModel right after ShowDialog

I have a ViewModel like this:

public class WelcomeWindowVm : ViewModel
{
    private ViewModel view;

    public WelcomeWindowVm(){
        this.View = new LoginVm() { 
            Completed += (o, e) => {
                this.View = new OtherVm(e.User){ 
                    Completed += (o, e) =>; // and so on
                } 
            }
        };
    }

    public ViewModel View {
        get {
            return this.view;
        }

        set {
            this.view = value;
            this.OnPropertyChanged(nameof(this.View));
        }
    }
}

LoginVm is another Viewmodel whose Completed event is triggered when a Command on it is completed (The event is only triggered when correct login credentials are used). OtherVm is another vm whose completed event is triggered for whatever reason.

I render the View using a DataTemplate . For example:

<Window.Resources>   
   <DataTemplate DataType="vm:LoginVm">
         Textboes and buttons here
    </DataTemplate>
    <DataTemplate DataType="vm:OtherVm">
        ...
    </DataTemplate>
</Window.Resources>
<ContentControl Content={Binding View} />

The DataContext of this window is set to WelcomeWindowVm class above, before ShowDialog .

This works well. When the Window is shown using ShowDialog, LoginVm is shown. Then OtherVm when whatever task of LoginVm is completed, and so on.

Now I thought of converting the Completion stuff to Async/await pattern. The LoginVm now looks like this:

public LoginVm{
    ...
    private TaskCompletionSource<User> taskCompletionSource = new TaskCompletionSource<User>();
    ...
    // This is the Relay command handler
    public async void Login()
    {
        // Code to check if credentials are correct
        this.taskCompletionSource.SetResult(this.user);
        // ...
    }

    public Task<User> Completion(){
        return this.taskCompletionSource.Task;
    }
}

Instead of this:

public LoginVm{
    public event EventHandler<CustomArgs> Completed;

    // This is the Relay command handler
    public async void Login()
    {
        // Code to check if credentials are correct
        OnCompleted(this.user);
        // ...
    }
}

So that I can use it like this:

public WelcomeWindowVm(){
    var loginVm = new LoginVm();
    this.View = new LoginVm();
    User user = await loginVm.Completion();

    var otherVm = new OtherVm(user);
    this.View = otherVm;
    Whatever wev = await otherVm.Completion();

    //And so on
}

But I can't use await in a Constructor and even if I use an async Method for that, how will I call it in another class after calling ShowDialog since ShowDialog blocks?

I think using an async void will work. But from what I have heard, it should be avoided unless I am using it in an event handler.

Maybe use an async Task method but not await it?

You can do it like this:

    public WelcomeWindowVm() {
        var loginVm = new LoginVm();
        this.View = loginVm;
        loginVm.Completion().ContinueWith(loginCompleted =>
        {
            var otherVm = new OtherVm(loginCompleted.Result);
            this.View = otherVm;
            otherVm.Completion().ContinueWith(whateverCompleted =>
            {

            });
        });
    }

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