ReactiveUI - View Locator performance

1.7k views Asked by At

In my WPF application which makes use of ReactiveUI, I've noticed an area of poor performance.

I have a view-model which contains a lot of other lightweight view-models (think 30ish). These nested view-models are simple, usually representing a button each. They're all displayed within a user control, inside an ItemsControl which is wired using ReactiveUI's OneWayBind. This means that each item is displayed using ViewModelViewHost.

So, the problem

On my powerful desktop PC, when I navigate to this view-model, there is a noticable delay between pressing the "go-to-view-model" button and the view changing, around 0.5 seconds. When I run the same software on a Power-PC, the delay is nearly 4 seconds. This is a pretty big issue from an UX point of view.

What I've learned

I tried profiling and debugging my code for a long time, and found no problem areas. Zilch (note: using JustMyCode in VS so ReactiveUI didn't show up). I did however, find a way to remove the issue. Instead of binding to the ItemsControl.ItemSource with OneWayBind, I did so in XAML, as such:ItemSource={Binding MyViewModels} and setting the DataTemplate manually. This results in a much quicker transition.

When you bind with OneWayBind with an ItemsControl, a ViewModelViewHost is automatically created for you, and the ViewLocator is used to find the view for your view-model. I'm assuming this is very slow for some reason.

Question

Is anyone aware of how I can get around this performance hit without having to manually define lots and lots of data-templates for an ItemsControl? If I have view-models of view-models of view-models, then things tend to get ugly very quickly. From my past experiences with Caliburn.Micro, the view-location conventions were very quick, so I'm also wondering if I'm not quite using ReactiveUI properly, and that there is an alternative approach which is quicker.

Thank you.

TLDR;

ViewModelViewHost as a DataTemplate for ~30 view-models causes views to be very sluggish when initially loaded, leaving the UI to look as if it has crashed. Is there any way to avoid this?

2

There are 2 answers

0
Contango On

I've run into this exact same problem before.

Essentially, you want to show/hide, rather than create/destroy.

Creating a new visual tree is lots of work, and you will typically get delays of seconds or more when you switch tabs.

Now if you create everything, then collapse what you dont need and show it on demand, suddenly everything updates in an eyeblink.

It may take a bit of refactoring to do this, and the code may not look as clean, but it sure as hell runs blazingly fast.

3
Gluck On

I believe the root cause of this issue is an implementation issue of TransitioningContentControl.

This control (which has many existing implementations all over the place, most of which originated from Silverlight one AFAICT) will cause an extra load/unload transition when navigating out of a content.

The current control will trigger Unload/Load/Unload when navigating out, instead of single Unload. This issue is referenced in many places.

When used in RxUI, this bug causes WhenActivated to be called on the leaving View, causing performance issues, especially if the current view is complex.

TransitioningContentControl should be re-written to avoid this extra transition, here's an sample implementation which doesn't suffer from this issue.