MVVM-PRISM, how to display multiple instances of a view in a region

Topics: Prism v2 - Silverlight 4, Prism v4 - Silverlight 4
Oct 18, 2010 at 2:18 PM

Hi,

I need to display multiple instances of a OrdersDetailsView.xaml within a region placed in OrdersView.xaml.

I have an OrdersView XAML that contains an ItemsControl tag defined like this:

<ItemsControl x:Name="OrdersItemsControl" BorderThickness="0" cal:RegionManager.RegionName="OrdersRegion" Margin="0,10,0,10" />


Within the ItemsControl in my OrdersView I want to display multiple instances of a OrderDetailsView. I'm able to add _one_ OrderDetailsView, but as soon as I try to add more than one it fails with "View already exists" or similar errormsg... This is how I add an instance of OrderDetailsView:

Dim OrdersRegion = _RegionManager.Regions("OrdersRegion")
Dim view = _Container.Resolve(Of OrdersDetailsView)()
Dim viewmodel = _Container.Resolve(Of OrdersDetailsViewModel)()

view.ApplyModel(viewmodel)
OrdersRegion.Add(view, "OrdersDetailsView")
OrdersRegion.Activate(view)


I understand that replicating this code for each orderdetailsview I'm creating is not correct, but I dont see clearly how to do it. I somehow need a collection of views or something? Any help is appreciated!

Oct 18, 2010 at 6:29 PM
Edited Oct 18, 2010 at 6:29 PM

Hi,

The problem that you are experiencing is because you are using the same name for all views instances ("OrdersDetailsView"). So, if you need to identify your view in the region, you could use a different name for each instance or avoid passing a name as shown below.

Option 1:

var mainRegion = this.RegionManager.Regions["MainRegion"];
mainRegion.Add(new OrdersDetails(), "OrdersDetails1");
mainRegion.Add(new OrdersDetails(), "OrdersDetails2");

Option 2:

var mainRegion = this.RegionManager.Regions["MainRegion"];
mainRegion.Add(new OrdersDetails());
mainRegion.Add(new OrdersDetails());

Hope this helps.

Fernando Antivero
http://blogs.southworks.net/fantivero

Oct 19, 2010 at 8:21 AM
fantivero wrote:

Hi,

The problem that you are experiencing is because you are using the same name for all views instances ("OrdersDetailsView"). So, if you need to identify your view in the region, you could use a different name for each instance or avoid passing a name as shown below.

Option 1:

var mainRegion = this.RegionManager.Regions["MainRegion"];
mainRegion.Add(new OrdersDetails(), "OrdersDetails1");
mainRegion.Add(new OrdersDetails(), "OrdersDetails2");
 
Option 2:

var mainRegion = this.RegionManager.Regions["MainRegion"];
mainRegion.Add(new OrdersDetails());
mainRegion.Add(new OrdersDetails());

Hope this helps.

Fernando Antivero
http://blogs.southworks.net/fantivero

 Thanx, that solved my problem! :)

I'm really wondering about if my approach to this is correct/the best way to do it. Each instance of OrderDetails view must have it's own set of data from the attached viewmodel. So - if I have a few OrderDetails view's in my region in the ItemsControl will I be able to access the data in each one of them or is there a way I should structure this better?

 

Oct 19, 2010 at 12:55 PM

Hi,

This is a possible approach for your scenario, since a similar scenario is implemented in the Stock Trader RI when buying different stocks simultaneously.

So, if you need more guidance on this topic, you could also take a look at this Reference Implementation application.

Hope this helps.

Fernando Antivero
http://blogs.southworks.net/fantivero

 

 

Oct 19, 2010 at 1:22 PM

Hi,

Yes, the Stock Trader RI is acually where I got my idea from :)

But, I'm having trouble following the code in the Reference Implementation, I find it hard to read. So I was looking for a simpler solution, or simpler solution of the approach in the Stock Trader... Preferably in VB.NET, but no luck so far.

I will continue my approach, but if someone can come up with a simple sample or better way for me to look at it I will be happy! :)

Oct 19, 2010 at 1:33 PM

Hi,

I think that you can find interesting the following download link, since it contains the Prism v2 (old version), but in Visual Basic .Net. I am not sure whether it contains the Reference Implementation or not, but I think that it might help you.

http://www.microsoft.com/downloads/en/details.aspx?displaylang=en&FamilyID=537da1cd-43e1-4799-88e7-a1da9166fb46

Hope this helps.

Fernando Antivero
http://blogs.southworks.net/fantivero

 

 

Oct 19, 2010 at 2:12 PM

Thanx, I already have that VB version of PRISM v2, sadly the Stock Trader app is only in C# in v2 and the latest release.

If you have time, can you please help me understand this..:

Why is this code giving me 2 OrdersDetailsView BOTH with Orders ZZZ, I would have hoped that I got one view with Orders XXX and one with Orders ZZZ:

    Dim OrdersRegion = _RegionManager.Regions("OrdersRegion") 
 
    Dim viewX = _Container.Resolve(Of OrdersDetailsView)() 
    Dim viewmodelX = _Container.Resolve(Of OrdersDetailsViewModel)() 
 
    viewmodelX.OrdersName = "Orders XXX" 
    viewX.ApplyModel(viewmodelX) 
 
 
    Dim viewZ = _Container.Resolve(Of OrdersDetailsView)() 
    Dim viewmodelZ = _Container.Resolve(Of OrdersDetailsViewModel)() 
 
    viewmodelZ.OrdersName = "Orders ZZZ" 
    viewZ.ApplyModel(viewmodelZ) 
 
    OrdersRegion.Add(viewX, "OrdersDetailsViewX") 
    OrdersRegion.Add(viewZ, "OrdersDetailsViewZ") 
Oct 19, 2010 at 2:29 PM
Edited Oct 19, 2010 at 2:31 PM

Hi,

The code seems to be ok. I mean, it should be displaying two different views, one for for "Orders XXX" and another different for "Orders ZZZ".

The only thing that might cause this behavior is the way that you used to register OrdersDetailsView and OrdersDetailsViewModel in the container. For achieving this scenario, they must be registered using the RegisterType method, so it will create a new instance when resolving OrdersDetailsViews/OrdersDetailsViewModel.

Additionally, in the ApplyModel method, is it just for setting the DataContext property?

Hope this helps.

Fernando Antivero
http://blogs.southworks.net/fantivero

 

Oct 19, 2010 at 2:38 PM

Thanx so far!

This is how I register the View and Viewmodels in my module definition:

    Public Sub Initialize() Implements Microsoft.Practices.Composite.Modularity.IModule.Initialize
        RegisterServices()

        container.Resolve(Of IOrdersView)()
        container.Resolve(Of IOrdersViewModel)()
        container.Resolve(Of IOrdersDetailsView)()
        container.Resolve(Of IOrdersDetailsViewModel)()

    End Sub

    Private Sub RegisterServices()
        container.RegisterType(Of IOrdersViewModel, OrdersViewModel)(New ContainerControlledLifetimeManager())
        container.RegisterType(Of IOrdersView, OrdersView)()

        container.RegisterType(Of IOrdersDetailsViewModel, OrdersDetailsViewModel)(New ContainerControlledLifetimeManager())
        container.RegisterType(Of IOrdersDetailsView, OrdersDetailsView)()
    End Sub

 

The applyModel method is just:

Public Sub ApplyModel(ByVal datasource As Object) Implements Common.Interfaces.IView.ApplyModel
        DataContext = datasource
End Sub

The DataContext/Source is right now empty/nothing. I'm just testing my views/viewmodels by setting a property to "Orders ZZZ" and "Orders XXX" on the viewmodel that bind to my view.

 

 

Oct 19, 2010 at 2:45 PM

Hi,

That is the problem, when you use a unity Lifetime Manager (ContainerControlledLifetimeManager), the container will be providing a singleton instance of your types. So, you could use the following code:

Private Sub RegisterServices()
        container.RegisterType(Of IOrdersViewModel, OrdersViewModel)()
        container.RegisterType(Of IOrdersView, OrdersView)()

        container.RegisterType(Of IOrdersDetailsViewModel, OrdersDetailsViewModel)()
        container.RegisterType(Of IOrdersDetailsView, OrdersDetailsView)()
End Sub

Fore more information about Lifetime Managers, you could take a look at the following documentation section: Using Lifetime Managers

Hope this helps.

Fernando Antivero
http://blogs.southworks.net/fantivero

 

Oct 21, 2010 at 10:31 AM
Edited Oct 26, 2010 at 9:16 AM

Thank you very much, you're post is spot on. My problem was related to the singleton instance.

Please see my new problem in this thread:

http://compositewpf.codeplex.com/Thread/View.aspx?ThreadId=232334

:)