Skip to content

ShellViewModel Class

Richard Martin edited this page Mar 25, 2024 · 2 revisions

Bootstrapper.ViewModels.ShellViewModel

IsWaiting property

When the user runs the bundle, the detect phase starts and the UI is displayed. While the WiX engine runs, the UI should prevent the user from exiting the app or interfering with the action that WiX (or, more importantly, Windows Installer) is performing, except allowing the user to cancel. The easiest way to manage this is to disable everything in the UI except a cancel button while WiX is busy. The shell's view model uses the property IsWaiting to manage this. This property remains false until WiX completes the detect phase.

public bool IsWaiting => _model.State.BaStatus == BaStatus.Waiting;

The OnPropertyChanged method must be called to inform the view when the BA's status changes, so you'll see that implemented in several places in the VM.

IsPassive property

This property is true when a user runs the bundle with the -passive command line switch. When running passively, I wanted to remove most of the UI controls and only display a progress bar and a cancel button. I'm using BooleanVisibilityConverter to help with this. This converter has a Negate property that, when set, reverses the normal behavior that the converter provides. You'll see in the ShellView XAML some Grids that wrap other controls and disable or hide them based on VM boolean properties.

<Grid Visibility="{Binding IsPassive, Converter={util:BooleanVisibilityConverter Negate=True}}">

AfterDetect method

The BA calls this method when WiX's DetectComplete event is raised. If the BA is running passively, then a follow up action will be sent to let the view model know which action is scheduled.

The first order of business is to inform the view that the BA's status has changed.

OnPropertyChanged(nameof(IsWaiting));

Instead of presenting a series of buttons to the user - install, uninstall, update, repair - and disabling the ones that the user can't use, only the buttons that are valid will be shown. The VM exposes ExecuteCommand and ExecuteDescription properties that can be bound to a single button. We determine which action will be assigned to this button by updating these two properties.

if (_model.State.RelatedBundleStatus == BundleStatus.OlderInstalled ||
    followupAction == LaunchAction.UpdateReplace ||
    followupAction == LaunchAction.UpdateReplaceEmbedded)
{
    ExecuteCommand = _updateCommand;
    ExecuteDescription = "Update";
}
else if (_model.State.RelatedBundleStatus == BundleStatus.Current ||
         followupAction == LaunchAction.Uninstall ||
         followupAction == LaunchAction.UnsafeUninstall)
{
    ExecuteCommand = _uninstallCommand;
    ExecuteDescription = "Uninstall";
}
else
{
    ExecuteCommand = _installCommand;
    ExecuteDescription = "Install";
}

After that, we determine whether to display the Repair button or not. A method named AssignMessage is also called. This constructs a message that lets the user know status of the install.

IsRepairAvailable = _model.State.RelatedBundleStatus == BundleStatus.Current;
AssignMessage();

Now that the VM's state has been updated to reflect the model's state, we can refresh all of the VM's commands.

CommandManager.InvalidateRequerySuggested();

AfterApply method

Similar to AfterDetect, this method is called when the install completes. It just resets the progress display and calls AssignMessage to let the user know how the install went.

ProgressVm.Reset();
AssignMessage();

We also ensure the VM's commands are refreshed.

CommandManager.InvalidateRequerySuggested();

Previous: ProgressHandler Class || Next: ConfigViewModel Class

Clone this wiki locally