notify View(Models) of closing the program
Asked Answered
P

1

5

So I got my prism/mvvm/mef program running nicely along, the user is entering data in the application, then closes the application (or shuts down the computer).

How can I get my View(Model) notified of the program closing / the computer shutdown, so it can either save the users data or maybe ask if these should be saved?

Losing data on program close is definitely something to be avoided, and it does not make sense to save stuff on every single keypress of the user.

Pica answered 16/12, 2010 at 9:36 Comment(0)
S
8

I expose CompositeCommands that clients can register to for interesting global "events", e.g.

public static class HostCommands
{
    private static readonly CompositeCommand Shutdown = new CompositeCommand();

    public static CompositeCommand ShutdownCommand
    {
        get { return Shutdown; }
    }
}

I trigger the shutdown command in my shell, e.g.

public Shell()
{
    InitializeComponent();

    Closing += (sender, e) =>
    {
        if (HostCommands.ShutdownCommand.CanExecute(e))
            HostCommands.ShutdownCommand.Execute(e);
    };
}

And clients can register as follows, e.g

public SomeViewModel(IEventAggregator eventService)
{
    //blah, blah, blah...

    HostCommands.ShutdownCommand.
        RegisterCommand(new DelegateCommand<object>(_ => Save()));
}

Update

I do not handle the cancel scenario, but you could implement this via the object which is passed to the command. For instance in the above code I pass in a CancelEventArgs which clients could manipulate i.e. by setting Cancel=true. I could inspect this value in my Shell closed event handler after the command has execute to derive whether I should cancel closing the shell. This pattern can be expanded on.

See answered 16/12, 2010 at 9:50 Comment(6)
Cool, looks great! Just wondering: in SomeViewModel you wrote "new Command(_ => Save())" - shouldn't this be "new DelegateCommand(() => Save())"?Pica
@Pica you are quite right. I have inherited from DelegatedCommand. I'll update the sample so it uses Prism types only.See
Oh, and I wonder if it might be better to use prism Eventing (loosely coupled events), so I don't need to worry about unbinding?Pica
When I first implemented this it seemed like the natural choice, and for this particular usage bindings last for the lifetime of the host, so unbinding isn't an issue. However, using the EventAggregator would also seem to be a good choice. A slight fly in the ointment is that strictly speaking the EA should not be used for two-way communication as is implied by the cancel pattern - that kind of violates the design intention. However, it would not be the end of the world to do this. Commands on the other hand support CanExecute\Execute explicitly.See
From experience, I'd recommend the command route. Commands guarantee that everything is executed before the application is closed - everything that has a handler must be called. Events introduce multithreading issues depending on how something subscribes, so you can get into race conditions where a handler is still working on doing its shutdown logic while the application itself has already terminated. Not a good place to be.Revelation
+1 @Matt Good point re. multi-threading. Commands are executed synchronously, whereas there is explicit support in EA to handle messages asynchronously. This could indeed lead to async actions being active when the host shuts down. Unfortunately there is nothing to stop people pinging off a thread in a command handler, but the pattern is more explicit re. commands vs the EA.See

© 2022 - 2024 — McMap. All rights reserved.