Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prism pop-up new window in WPF

Tags:

c#

mvvm

wpf

prism

How can I open/close a new window in WPF without violating rules of the MVVM pattern?
I just want to mimic the login module of ms office outlook.

I've already read this article, but there are an error in passing a parameter confirmation

I'm currently using prism 5.0.

like image 566
Neil Avatar asked Nov 28 '22 20:11

Neil


1 Answers

Luckily, Prism 5.0 (and I assume 6.0 too, haven't worked with it yet), has a class called InteractionRequest<T> which you can use from code to raise interaction requests.

An interaction request is basically a window, that asks the user for a certain action and calls a callback (if necessary or desired) with the users decisions/actions.

public class ShellViewModel : BindableBase
{
    private readonly IRegionManager regionManager;

    public ShellViewModel(IRegionManager regionManager)
    {
        if (regionManager == null)
            throw new ArgumentNullException("regionManager");

        this.regionManager = regionManager;
        this.OptionSettingConfirmationRequest = new InteractionRequest<IConfirmation>();

        openConnectionOptionsCommand = new DelegateCommand(RaiseConnectionOptionsRequest);
    }

    public InteractionRequest<IConfirmation> OptionSettingConfirmationRequest { get; private set; }

    private readonly ICommand openConnectionOptionsCommand;
    public ICommand OpenConnectionOptionsCommand { get { return openConnectionOptionsCommand; } }

    private void RaiseConnectionOptionsRequest()
    {
        this.OptionSettingConfirmationRequest.Raise(new Confirmation { Title = "Options not saved. Do you wish to save?" }, OnConnectionOptionsResponse);
    }

    protected virtual void OnConnectionOptionsResponse(IConfirmation context)
    {
        if(context.Confirmed)
        {
            // save it
        }

        // otherwise do nothing
    }
}

In XAML you would do something like

<Button Content="Options" Command="{Binding OpenConnectionOptionsCommand}">
    <i:Interaction.Triggers>
        <pit:InteractionRequestTrigger SourceObject="{Binding OptionSettingConfirmationRequest, Mode=OneWay}" >
            <pie:LazyPopupWindowAction RegionName="ConnectionSettings" 
                                NavigationUri="ConnectionSettingsView" IsModal="True" />
        </pit:InteractionRequestTrigger>
    </i:Interaction.Triggers>
</Button>

I used my own implemetation of PopupWindowAction (see github project page for it's implementation) called LazyPopupWindowAction, which will instantiate the embedded ConnectionSettingsView View on click. If you don't care that your view is instantiated only once, feel free to use PopupWindowAction, then it will be instantiated at the same time as the View containing the action.

It's basically copy & paste with cutting some useless lines from one of my projects. I used IConfirmation and INotification interfaces instead of the concrete implementations.

XAML with PopupWindowAction

<Button Content="Options" Command="{Binding OpenConnectionOptionsCommand}">
    <i:Interaction.Triggers>
        <pit:InteractionRequestTrigger SourceObject="{Binding OptionSettingConfirmationRequest, Mode=OneWay}" >
            <pi:PopupWindowAction>
                <pi:PopupWindowAction.WindowContent>
                    <views:CustomPopupView />
                </pi:PopupWindowAction.WindowContent>
            </pi:PopupWindowAction>
        </pit:InteractionRequestTrigger>
    </i:Interaction.Triggers>
</Button>

Namespace declarations

xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
xmlns:pi="clr-namespace:Microsoft.Practices.Prism.Interactivity;assembly=Microsoft.Practices.Prism.Interactivity"
xmlns:pit="clr-namespace:Microsoft.Practices.Prism.Interactivity.InteractionRequest;assembly=Microsoft.Practices.Prism.Interactivity"
xmlns:pie="clr-namespace:MyProject.UI.Prism.Interactivity;assembly=MyProject.UI"

Update: Since people keep asking about the LazyPopupWindowAction, I've put the source in a GitHub Gist. Basically it's based on the PopupWindowAction from Prims 5 (and for Prism, haven't test it with Prism 6 yet, probably won't work w/o adjustments) and does the exact same thing, but also adds Region and Navigation support with the opened window, something that I needed in my application.

One thing I disliked about the default implementation was, that the view and it's viewmodel will be instantiated at the same time the Shell gets instantiated and the ViewModel remains in it's state, when you close it (it was actually just hidden).

like image 144
Tseng Avatar answered Nov 30 '22 10:11

Tseng