Display Child window WPF

Topics: Prism v4 - WPF 4
Jan 9, 2013 at 10:28 AM

Hi

An application I am working on has a Shell window with a MainRegion for displaying views and NavigationRegion for my navigation buttons/links.

A Client entity has a collection of Notes, notes can also be attached to other entities such as appointments etc... to this end I have added a NotesModule to my solution.

My thinking is that when user selects to add a new note or view existing note I will get UnityContainer to knock me up a NotesEditView as a "ChildWindow" and display modally but am wondering how I would go about this with the PRISM architecture. I have implemented a Confirmation & Notification popup mechanism that I found on the web, and am thinking this may the way to go for "ChildWindows" style windows to capture data outside of the current View.

Does anyone know of any nice simple examples as I can't seem to find any?

Thanks in advance.

Developer
Jan 9, 2013 at 4:54 PM

Hi,

I believe you might find the following blog post interesting, where I proposed an approach (along with a sample application) to show views in popup windows using InteractionRequests based on a port from the Prism's PopupChildWindowAction to WPF:

I hope you like it,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Jan 10, 2013 at 9:35 AM

Do you know what, I think this is where I robbed your Notification/Confirmation implementation from :) I'll have another look and see if I can figure how this would be used by a view/viewmodel in a module to interact with the DB and then return some eventargs back to the calling view model. Does that sound like the correct approach to you?

Thanks for all your help past week or so, really is appreciated squire.

Developer
Jan 10, 2013 at 12:40 PM

Hi,

This seems like a feasible approach to me as while the user interacts with the pop-up window, the context object passed when raising the InteractionRequest is updated according to the bindings defined in that pop-up window, and after the user closes the pop-up window, this updated context object is passed back to the calling view model, along with any updated values through the callback method, allowing you to receive this information in the calling view model to react accordingly. An example of this approach could be the SelectItemRequest of the above mentioned sample.

Regards,

Agustin Adami
http://blogs.southworks.net/aadami

Jan 10, 2013 at 12:47 PM

You guys are the kings.... Cheers

Jan 10, 2013 at 12:47 PM

You guys are the kings.... Cheers

Jan 10, 2013 at 7:26 PM
Edited Jan 10, 2013 at 7:30 PM

Can I mither you chaps again? I'm trying to get my notes module up and running and have the view and view model created and have a NoteEditFinished class inheriting the : CompositePresentationEvent<t> class for my event, I assume, but as this is contained in it's own module, how would my ClientViewViewModel know about the NoteEditFinished class without a holding a reference to the NotesModule?

I thought my modules should not be coupled in this way?

Thanks if you can help me yet again :)

**Edit**

I thought of adding the NoteEditFinished : CompositePresentationEvent<Note> to the Infrastructure project I ripped off from your example but know this must be aware of my ClientModuke(as that is where I currently have the EntityFramework and dataContext classes), does this follow the pattern?

Developer
Jan 11, 2013 at 12:44 PM

Hi,

In my opinion, I would consider moving the models classes to a separate project that could be referenced by all the different modules that requires them, as Damian suggested in this previous thread (WPF PRISM modular design). This shouldn't be wrong, as Prism recommends that modules should not reference each other, but not that they shouldn't share common projects between them if required.

Regarding this topic, I believe you could also find the following threads interesting, where similar discussions have been addressed:

I hope you find this handy,

Agustin Adami
http://blogs.southworks.net/aadami

Jan 11, 2013 at 1:32 PM

Hi Agustin, I undertook the re-architecture exercise last evening as I remembered Damian advising, that was spot on and I got the child window to load but when my OnEditNote method fired all that was displayed seemed to be an instance of the Notification Window from the Infrastructure project I borrowed from you guys, how is the application supposed to figure out that upon my Interactionrequest, and injecting the EditNoteViewViewModel, that the window which needs displaying is my EditNoteView? I am tied up knots.

 

Thanks for any help you can offer an ailing developer.

Jan 11, 2013 at 3:01 PM

Never mind Augistin, I just inspected the XAML of the HelloWorldView and think I've found the way you have worked this, with the

 

<inf_int:PopupWindowAction.WindowContent 
>
<local:SelectItemView 
/>
</inf_int:PopupWindowAction.WindowContent 
>

 

 

 Code..... genius....

 

Jan 12, 2013 at 1:28 PM

Agustin, I am, unsurprisingly, confused again, my view and view model for creating/editing/viewing a note are contained in a NoteModule. With the examples you geniuses have developed the code to fire the modal/"ChildWindow" effect your view and view models reside in the same project, selectItem method requires a reference to, or knowledge of, the SelectItemViewModel as below:

this.SelectItemRequest.Raise(
    new SelectItemViewModel { Title = "Items" },
    (vm) =>
    {
        if (vm.SelectedItem != null)
        {
            Result = "The user selected: " + vm.SelectedItem;
        }
        else
        {
            Result = "The user didn't select an item.";
        }
    });

If SelectItem was a View&ViewModel in a separate module how would you guys go about raising the interaction request for the view model? Also, to see if I could get the Note editor to show with the method you show, I added a reference in my Client module to my Note module and tried the following:

private void OnAddNewNote()
{
    _unityContainer.RegisterInstance<NoteViewViewModel>(new NoteViewViewModel(this._dbContext, 0));
    this.AddNewNoteRequest.Raise(_unityContainer.Resolve<NoteViewViewModel>(),
        (cb) =>
        {
            int i = 0;
        });
}

 As you can see I use a UnityContainer to register and instance of my NoteViewViewModel and pass the parameters I require then raise the AddNewNoteRequest passing in the view model resolved by unity but the method fails as I have not set the Notification windows' Title property, how can I set this using the above code?

Sorry if I am totally missing something, and many thanks for your assistance with my learning curve, this architecture is a big step away from the old "code behind" days....

Thanks

Developer
Jan 14, 2013 at 2:25 PM

Hi,

Based on my understanding, when following the approach you mentioned you should be able to set the Title property to the resolved instance before raising the InteractionRequest as the NoteViewViewModel should inherit from the Notification class. For example this could be achieved like this:

private void OnAddNewNote()
{
    _unityContainer.RegisterInstance<NoteViewViewModel>(new NoteViewViewModel(this._dbContext, 0));

   NoteViewViewModel myNoteViewViewModel = _unityContainer.Resolve<NoteViewViewModel>();

   myNoteViewViewModel.Title="NoteTitle";
 
    this.AddNewNoteRequest.Raise(myNoteViewViewModel,
        (cb) =>
        {
            int i = 0;
        });
}

However, fully decoupling these components may not be straightforward if following this approach, this is mainly because the InteractionRequest class uses the Notification class as a base class, in which case as mentioned in the following work item:

Some changes should be implemented to allow more complex scenario, like re-implementing the IInteractionRequest interface to allow passing an interface instead of the Notification class, this could be helpful in order to resolve complex contexts from the container that could implement this interface, allowing to decoupled your view model through this interface.

On the other hand, as you may find in Damian Cherubini's blog post, you could also use another approach to pass your view model to your view:

The view could inject its own view model through dependency injection (using the ServiceLocator) which wouldn’t require for the view model to inherit from Notification and would decouple the popup view model from the invoker view model. However, your view and view model would not be able to interact with the Notification passed in the InteractionRequest (I will explain how to solve this in the following section).

Perhaps, this approach could become handy, if decoupling these components is required (an example of this can be seen in the SelectClientRequest of the above mentioned sample).

I hope this helps,

Agustin Adami
http://blogs.southworks.net/aadami

Jan 14, 2013 at 4:47 PM

Once again thanks for your help, really great of you guys. I think I'm going to simply have my Client module, and any other module having entities where notes can be introduced, hold a reference to the Notes module. The above solutions sound like a decent amount of effort is going to be required to refactor the projects to work in this fashion. No doubt I'll stumble across this issue in the next module I am adding to the solution. Beginning to wonder if I should have opted for one of the "lighter" frameworks such as MVVM light?

Thanks again sir.

Developer
Jan 15, 2013 at 6:13 PM

Hi there,

Usually, a view that is being shown through an InteractionRequest is somewhat related to its "host" view, and this includes their corresponding view models. You could think of the "popup view" as an "extension" of the host view. Hence, as described by Agustin, using an InteractionRequest for views / view modules that you want to reuse in different modules (while maintaining them decoupled) could not be straight forward. This is mainly because you need to use the "popup view" in the "host view's" XAML code, and your custom Notification object passed to the InteractionRequest cannot be exported in the container through an interface.

Although there might be some workarounds to be able to decouple the popup view in a different module, I believe using RegionPopupBehaviors might be a more suitable approach. Basically, this behavior allows you to register a region that, when a view is injected in it, it will be shown in a new window. As this still acts like a common region defined in a RegionManager, you could use it like any other region. For example, instead of raising an InteractionRequest you could just add the view to the region through the Add method and the view should be shown in a new window. However, in this case you would be able to decouple the view / view model from the "host," as you will not be limited by XAML nor by the Notification class, thus allowing you to put them in a decoupled separated module. The drawback is that you don't have a built-in functionality to pass information from the "host" view model to the popup, but this could be achieved for example by using the EventAggregator, adding the popup view to the popup region through a navigation request (where you can pass parameters,) etc.

The RegionPopupBehaviors can be found in the Stock Trader Reference Implementation that is shipped with Prism.

I hope you find this useful,

Damian Cherubini
http://blogs.southworks.net/dcherubini

Apr 22, 2013 at 3:04 PM
Edited Apr 22, 2013 at 3:26 PM
OK, I got it