Nested ViewModels

Mar 2, 2012 at 8:22 AM

Hello Geert van Horrik


Continiue the discussion of Codeproject: Catel-Part-3-of-n-The-MVVM-Framework Nested ViewModel

I think i made something wrong.I generate to examlples. One with Code in ViewBase an one with code in behavior. Both don't work. Where Can i upload the examples?

Mar 2, 2012 at 8:29 AM

Hi,

try to see this example: https://skydrive.live.com/redir.aspx?cid=adeb7e738b27f26c&resid=ADEB7E738B27F26C%21106&parid=ADEB7E738B27F26C%21105 (really sorry, some problem to add hyperlink).

try also to see here : http://catelexamples.codeplex.com/

Mar 2, 2012 at 9:03 AM
Edited Mar 16, 2012 at 11:19 AM

Hello,

thanks for your answer. But this does not solve my problem. Because my problem is not the nested view models itself. Please read the discussion before on Codeproject so i do not have to repeat everything. So where can i upload my repro?

Mar 2, 2012 at 9:50 AM

You can create a new issue here, then upload your examples. I will take a look at it today once you have uploaded them.

Mar 2, 2012 at 9:59 AM

Ok i have uploaded 2 examples.

http://catel.codeplex.com/workitem/7084

Thanks

Mar 2, 2012 at 10:46 AM

It seems to be "normal" behavior for a tabcontrol in combination with data templates. It doesn't keep the views in memory (but actually removes everything) and re-creates it again when the page is loaded again. All other controls re-use the existing control and invoke the Loaded event again on the same instance.

So, if you are binding to a tab control with data templates, you cannot use the CloseViewModelOnUnloaded feature.

Mar 2, 2012 at 12:13 PM

Oh. Thats not good. So i can't use catel. It's very very slow when you open a Tabcontrol with lots of nested usercontrols on it. And every time you change to the focus of a tab you have to wait.

Mar 2, 2012 at 12:23 PM

Catel also supports setting the VM on front, just like any other MVVM framework. You just can't use the automatic view model creation logic.

Mar 2, 2012 at 12:29 PM

Yes but my intention was to use nested usercontrols. And i thought this is the only way to use this feature in catel. Or is there any other way, to nest your models but not your viewmodels?

Mar 2, 2012 at 4:38 PM

You can always choose to bind directly on models (just like other MVVM frameworks), or create a list of view models on a view model (just like other MVVM frameworks). Another way could be to create some kind of custom ViewModelManager which keeps your view models alive that you need. Then you can easily re-bind the view models in a user control, and still use the nested stuff.

But, to be honest, most implementations I see create a custom tab control implementation simply because they do not want the view to be unloaded. So most people create a custom tab control that hide a tab instead of remove it from the visual tree, but I have no clue how your application requirements are, so this is up to you.

Mar 5, 2012 at 2:13 PM
GeertvanHorrik wrote:

or create a list of view models on a view model (just like other MVVM frameworks).

Yes, but when we go back to your first answer on Codeproject

GeertvanHorrik wrote:

I would never go for nested view models

An Antagonism.

Mar 5, 2012 at 2:17 PM

Well, it wasn't meant that black & white. What I meant is: I would prefer a custom tabcontrol implementation instead of using nested view models. However, MVVM is a guidance to implement a good separation of concerns and to improve testability. With the development of Catel, we try to provide as much tools as possible because these are all "real-world" problems we encountered (not just to develop a theoretical framework).

Therefore, we also support "less-pure" implementations without having to switch to another framework. But hey, in the end it is your choice, you are free to use whatever you want.

Mar 5, 2012 at 2:55 PM

Yes, for sure. But we started here

GeertvanHorrik wrote:
you should definitely go for Catel, it is the only MVVM framework that can actually solve this issue for you.

That was the main reason wy i want use catel. Now i have to solve it myself. It was also my opinion to have nested models but not nested viewmodel. But i have no idea or solutoin to solve this.

My question was: Nested ViewModels with Models inside or Nested Viewmodels with reference to Nested Models?

It was a good idea to have only nested models and solve it with usercontrols and dynamic Viewmodels. But its to slow.

 

PS: I hope you can understand my not perfect english

Mar 5, 2012 at 3:01 PM

It does. Unfortunately, the TabControl in WPF behaves a bit off than the rest of the framework when you are using data templates. When you don't use data templates, it works perfectly.

So, this makes it "harder" if you want dynamic tabs based on the model (or view model) type. You have two options here:

1) Stick with the tab control and nest view models instead of models => directly bind these view models on a user control (just like any other MVVM framework)

2) Create a custom tab control which plays with the visibility and does not actually remove unloaded tabs from the visual tree. I prefer this option because it brings both speed and full control of what happens.

In real world applications I have experienced with both, and in the end always ended up in the second. But, I prefer having control and allow myself to move away from standard controls if necessary. Maybe for you these parameters are different and you love to stick with default controls and don't care about control at all.

So, again, I would go for a simple view with an observablecollection (which is on your view model), and have a SelectedItem on the view model. Then simply set the visibility of a grid or panel and this way you have a new tab control created very easily. Then you still have full control *and* you can use the nested user controls.

Mar 6, 2012 at 10:17 AM

Ok. So i try to write my own tabcontrol. Perhaps you would have a example for me? Somewehre in the net?

Mar 6, 2012 at 6:04 PM

Will think about it, but currently too busy with the 3.0 release (which we hope to ship ASAP, today we released beta 1).

Mar 7, 2012 at 7:12 AM

Hy Again. Find something interessted.

Keeping the WPF Tab Control from destroying its children: http://eric.burke.name/dotnetmania/2009/04/26/22.09.28

So I can use the default tabcontrol. And now its fast.

Maybe you cad add this to catel 3.0 ;-)

Mar 7, 2012 at 7:59 AM

Nice! Maybe we can add this to the 3.0 release this week :)

Mar 7, 2012 at 2:46 PM

So now i take the example an made a custom control on it. Only the property CloseViewModelOnUnload dont matter. So the ViewModel always keep in mind.

Mar 8, 2012 at 9:25 AM

Tonight I will investigate the tab control and see what we can do. It will not work in SL because SL misses too many features, so we might have to introduce a second TabControl for SL. For WPF, it shouldn't be too much work.

Mar 8, 2012 at 12:15 PM

Hello. I can upload my Customcontrol TabControl. It works.

Mar 8, 2012 at 1:04 PM

Please do. You can create an issue (which can also be a task) and attach your control. Then we might be able to use it directly.

Mar 8, 2012 at 4:05 PM
Edited Mar 8, 2012 at 4:07 PM

Ok. I have added it. http://catel.codeplex.com/workitem/7096

But i dont' know how to change the type to task.

Mar 8, 2012 at 5:50 PM

Thanks, we appreciate this. We will try to make this into Catel 3.0.

Mar 15, 2012 at 4:00 PM

Hello Geert

Now i tested again with the tabcontrolext an nested viewmodel. And it's now faster when i change a tab. Because the viewmodel keep in mind.

But the problem at the startup has remained. When i have nested usercontrols its been very slow agains datatemplate in one file.

My Application needs to start about 10 seconds with nested usercontrols. With Datatemplate in one file it only takes abut 2 seconds.


Mar 15, 2012 at 4:15 PM

How many items are in the list? If possible, can you upload the files, then I can check the performance using a performance profiler.

Mar 16, 2012 at 8:57 AM

Oh. Thats not possible sorry. But I found something which is responsible for that i think. When i open a nested  view the constructor of the associated viewmodel is called twice. But at the moment i don't know why. The Firstime the the calls are fast the second time its very slow.

Maybe you have an idea what i made wrong?

Mar 16, 2012 at 10:37 AM

In 2.5, we fix this bug:

(x) Fixed issue where the Nested User Controls would construct a view model twice for the same model

However, it might be possible that something like this is happening again. Does your view model have both a default constructor and an injection constructor? If you want, you can also email me the project, then it won't be public.

Mar 16, 2012 at 10:58 AM

The problem is that there is a Database behind. Without this database the application don't work.

I try to explain transfered my Names to your example.

So I have 1 House and 2 Rooms

With an debugconverter on

<ItemsControl Grid.Column="1" ItemsSource="{Binding Path=Rooms, Converter={StaticResource debugConverter}}">

The stackcall:

1. Constructor of Houseview

2. Coverter return value -> count 2 (Room_1 / Room2)

3. Constructor RoomView. 2 Times.

4. Constructor of HouseViewModel

5. Coverter return value -> count 2 (Room_1 / Room2)

6. Constructor RoomViewModel. 2 Times

Now Again

7.  Constructor of RoomView. 2 Times.

8. Constructor RoomViewModel. 2 Times

Mar 16, 2012 at 11:07 AM

And I also start the example Advanced Demo with 1 House and 2 Rooms and the converter (UserControl in Behavior)

The stackcall:

1. Constructor of Houseview

2. Coverter return value -> count 2 (Room_1 / Room2)

3. Coverter return value -> count 2 (Room_1 / Room2)   (why this ??)

4. Constructor of HouseViewModel

5. Coverter return value -> count 2 (Room_1 / Room2)

Expand Rooms

6. Constructor of RoomView. 2 Times.

7. Constructor RoomViewModel. 2 Times

So only call the RoomView and it's associated ViewModel 2 Times for the 2 Room's . And not 4 Times as in my example. But why the converter is called so often I also don't know why.

Mar 16, 2012 at 11:26 AM

Oh I forgot

 Does your view model have both a default constructor and an injection constructor? If you want, you can also email me the project, then it won't be public.

No, only the injection Constructor.

Mar 16, 2012 at 1:26 PM

The binding itself is updated because the UserControl wraps itself in a WarningAndErrorValidator object (gets detached from the visual tree for a moment). The examples only construct the view models once.

Why your view model is constructor twice might be because you first create an empty collection, and then set it again with a filled collection? If so, I think it is better to call ReplaceRange (extension method in Catel) on the observable collection.

Mar 16, 2012 at 2:03 PM

Hello.

Ok tanks for the ReplaceRange Tipp. But thats not the problem. I create a emptycollection. But only add things don't set to a new collection.

The problem is that the view is also called twice. And i don't know why.

Mar 16, 2012 at 2:58 PM

Strange. I Add one more nested usercontrol. This view is called 3 times.

Mar 16, 2012 at 3:03 PM

Thus every level you go deeper, the view gets called one more time, is that the behavior you see?

Mar 16, 2012 at 3:19 PM

Yes i tried the next one. And there is always plus 1 call.

Mar 16, 2012 at 3:27 PM

And the time multipied with 2 ;-(

Mar 16, 2012 at 3:47 PM

This does not happen with the samples. Something is clearly going wrong, but without a repro I cannot debug it. I see the constructor of the view nicely gets called only once per view. Same for the view models, only one constructor per view.

Mar 19, 2012 at 10:28 AM
Edited Mar 19, 2012 at 10:28 AM

Hello.

I changed your example and add one more view: Part. So now a House has a Room. And a Room has a Part.

And now the example has the same behavior. I generate one house, one Room, one Part.

The Housview is called once, the roomview twice and the PartView triply.

I add the example here:

http://catel.codeplex.com/workitem/7104

Example in "LogicInBehavior"

Mar 20, 2012 at 3:08 PM

The next test. Try with 10 houeses 5 rooms an 4 Parts. And then you have to wait. Or maybe add one more level. And implement a little bit code in the viewmodels. Like in my Project. 10 Minutes to wait is normal :-(

Mar 22, 2012 at 7:07 AM

Hello

I see you fixed the corresponding isue. This comes up in 3.1 right. When do you release this. I need this urgent. When its not faster after that i have to change my strategy

Mar 22, 2012 at 8:28 AM

Here is a .NET 4.0 beta version:

http://dl.dropbox.com/u/8455721/catel_3.1_beta.zip

Mar 22, 2012 at 8:36 AM

Thanks. But i deploy in .Net 3.5

Mar 22, 2012 at 8:38 AM

Package is updated.

Mar 22, 2012 at 10:05 AM

Thanks. I have testet it. The views an its viewmmodel is no only created once. Its now faster. But only a little bit.

I changed the example an add one more view: Corner. I upload the example.

Mar 22, 2012 at 10:10 AM
Edited Mar 22, 2012 at 10:11 AM

Create an new issue or reopen the - Nested ViewModel. Constructor called view times - issue ?

Mar 22, 2012 at 11:26 AM

When I start my Application with a couple of objects the Application never comes up. When i break the debugging i see in the call stack that the Method

Catel.Collections.CollectionHelper.IsEqualTo(System.Collections.IEnumerable listA, System.Collections.IEnumerable listB)

will never left.

Mar 23, 2012 at 7:49 AM
Edited Mar 23, 2012 at 7:49 AM

So. I opened an new issue http://catel.codeplex.com/workitem/7110

Mar 23, 2012 at 10:20 AM

Is it also possible to get the source of catel 3.1 beta?

Mar 23, 2012 at 11:14 AM

Oh. The code is here under the point Source code. :-)

I have debugged your code. Because my app never comes up. I have found a bug. An endless loop in the

CollectionHelper.IsEqualTo

I open an New Issue.

Mar 23, 2012 at 11:21 AM

http://catel.codeplex.com/workitem/7111

Mar 23, 2012 at 1:50 PM

Great! Thanks for letting us know, we will fix this. And good that you are diving into the source code, let's hoipe you can find more improvements (we are always open for that).