ReactiveUI - View Locator performance - c#

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?

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.

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.

Related

Improve performance in big project c# WPF XAML [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 3 years ago.
Improve this question
We have a product (program) written in C# + WPF + XAML in our company. This is a fairly important program for us and it has been installed by many of our customers. But after switching to Framework 4.7.2, we noticed a strong performance degradation. We then changed to version 4.8, but the program still works quite slowly, especially the visual part.
In our program, we display data from a very large number of sensors (motion sensors, temperature, amount of light, etc.). We are constantly receiving new data that we process, save to the SQL Server 2014/2017 database, and then the client programs visualize this data.
The server part and communication, although complex, even works well on a not very powerful computer. But we have a very big problem with showing data on customer monitors.
The program is structured as follows: the client draws where he wants to see this data. For example, he has a black background and with lines he draws his factory. There are sensors in different places in this factory, he draws them in these places. Then he starts the scan and sees the result of the data where he drew the label. When there is little data, it is not very noticeable, but when there is a lot of data, moving the mouse between the data becomes inhibited, the client sees that the program is constantly slowing down and he needs to wait a few seconds, make some movement with the mouse and then again wait for the program to respond. If you do several things at once, then the program as if freezes. This is not so, but the feeling is that the program will now stop working.
I tried to use Debug and measurements of CPU and RAM but it practically did not help me in any way. Data is downloaded via web services from the server to the client program normally and takes up as much memory as needed. It’s hard to optimize it somehow. But when we start showing this data to the user, everything starts to work very badly. How to optimize data visualization so that the user continues to work calmly with the program? Will be glad to any advice.
What I did, which helped a bit to improve this virtualization in DataGrid tables. A little better for users, but this is not enough, you need something else, especially with the part that is drawn and shows labels with data in different places.
In my experience wpf is not suited for visualising large amount of data. It's fine for creating a fancy UI, but as the number of objects increase the performance drops dramatically. I tried everything from caching to freezing objects, and I concluded that I just chose the wrong technology. It doesn't utilise your GPU properly.
You can try converting to UWP, It might help.
Having that said, here are some tips you can also try:
Simplify your Visual Tree A common source of performance issues is a deep and complex layout. Keep your XAML markup as simple and shallow
as possible. When UI elements are drawn onscreen, a “layout pass” is
called twice for each element (a measure pass and an arrange pass).
The layout pass is a mathematically-intensive process—the larger the
number of children in the element, the greater the number of
calculations required.
Virtualize your ItemsControls As mentioned earlier, a complex and deep visual tree results in a larger memory footprint and slower
performance. ItemsControls usually increase performance problems with
deep visual trees because they are not virtualized. This means they
are constantly being created and destroyed for each item in the
control. Instead, use the VirtualizingStackPanel as the items host and
make use of the VirtualizingStackPanel.IsVirtualizing and set the
VirtualizationMode to Recycling in order to reuse item containers
instead of creating new ones each time.
Favor StaticResources Over DynamicResources StaticResources provide values for any XAML property attribute by looking up a reference to an
already defined resource. Lookup behavior for that resource is the
same as a compile-time lookup. DynamicResources will create a
temporary expression and defer lookup for resources until the
requested resource value is required. Lookup behavior for that
resource is the same as a run-time lookup, which imposes a performance
impact. Always use a StaticResource whenever possible.
Opacity on Brushes Instead of Elements If you use a Brush to set the Fill or Stroke of an element, it is better to set the Opacity on
the Brush rather than setting the element’s Opacity property. When you
modify an element’s Opacity property, it can cause WPF to create
temporary surfaces which results in a performance hit.
Avoid Using Run to Set Text Properties Avoid using Runs within a TextBlock as this results in a much higher performance intensive
operation. If you are using a Run to set text properties, set those
directly on the TextBlock instead.
Favor StreamGeometries over PathGeometries The StreamGeometry object is a very lightweight alternative to a PathGeometry.
StreamGeometry is optimized for handling many PathGeometry objects. It
consumes less memory and performs much better when compared to using
many PathGeometry objects.
Use Reduced Image Sizes If your app requires the display of smaller thumbnails, consider creating reduced-sized versions of your images.
By default, WPF will load and decode your image to its full size. This
can be the source of many performance problems if you are loading full
images and scaling them down to thumbnail sizes in controls such as an
ItemsControl. If possible, combine all images into a single image,
such as a film strip composed of multiple images.
Lower the BitMapScalingMode By default, WPF uses a high-quality image re-sampling algorithm that can sometimes consume system
resources which results in frame rate degradation and causes
animations to stutter. Instead, set the BitMapScalingMode to
LowQuality to switch from a “quality-optimized” algorithm to a
“speed-optimized” algorithm.
Use and Freeze Freezables A Freezable is a special type of object that has two states: unfrozen and frozen. When you freeze an object
such as a Brush or Geometry, it can no longer be modified. Freezing
objects whenever possible improves the performance of your application
and reduces its memory consumption.
Fix your Binding Errors Binding errors are the most common type of performance problem in WPF apps. Every time a binding error occurs,
your app takes a perf hit and as it tries to resolve the binding and
writes the error out to the trace log. As you can imagine, the more
binding errors you have the bigger the performance hit your app will
take. Take the time to find and fix all your binding errors. Using a
RelativeSource binding in DataTemplates is a major culprit in binding
error as the binding is usually not resolved properly until the
DataTempate has completed its initialization. Avoid using
RelativeSource.FindAncestor at all costs. Instead, define an attached
property and use property inheritance to push values down the visual
tree instead of looking up the visual tree.
Avoid Databinding to the Label.Content Property If you are using a Label to data bind to a String property, this will result in poor
performance. This is because each time the String source is updated,
the old string object is discarded, and a new String is created. If
the Content of the Label is simple text, replace it with a TextBlock
and bind to the Text property instead.
Bind ItemsControls to IList instead of IEnumerable When data binding an ItemsControl to an IEnumerable, WPF will create a wrapper
of type IList which negatively impacts performance with the
creation of a second object. Instead, bind the ItemsControl directly
to an IList to avoid the overhead of the wrapper object.
Use the NeutralResourcesLanguage Attribute Use the NeutralResourcesLanguageAttribute to tell the ResourceManager what the
neutral culture is and avoid unsuccessful satellite assembly lookups.
Load Data on Separate Threads A very common source of performance problems, UI freezes, and apps that stop responding is how you load
your data. Make sure you are asynchronously loading your data on a
separate thread as to not overload the UI thread. Loading data on the
UI thread will result in very poor performance and an overall bad
end-user experience. Multi-threading should be something every WPF
developer is using in their applications.
Beware of Memory Leaks Memory leaks are the number one cause of performance problems in most WPF applications. They are easy to have
but can be difficult to find. For example, using the
DependencyPropertyDescriptor.AddValueChanged can cause the WPF
framework to take a strong reference to the source of the event that
isn’t removed until you manually call
DependencyPropertyDescriptor.RemoveValueChanged. If your views or
behaviors rely on events being raised from an object or ViewModel
(such as INotifyPropertyChanged), subscribe to them weakly or make
sure you are manually unsubscribing. Also, if you are binding to
properties in a ViewModel which does not implement
INotifyPropertyChanged, chances are you have a memory leak.
Finally, a bonus tip. Sometimes when you have a performance problem it
can be very difficult to identify what exactly is causing the issue. I
suggest using an application performance profiler to help identify
where these performance bottlenecks are occurring in your code base.
There are a lot of profiler options available to you. Some are paid,
and some are free. The one I personally use the most is the Diagnosis
Tools built directly into Visual Studio 2019.
Blockquote
Source: https://dzone.com/articles/15-wpf-performance-tips-for-2019

Xamarin Forms app re-architechture due to memory leak(s)

Suppose I've got something like following
bunch of Data classes
bunch of List of most of the data classes
loads of List<List<List<Data>>> classes to represent at least 3D arrays
a good few App.MyViewModel view models used in different pages due to thread access
the viewmodels are quite complex to my liking with tonnes of properties linking back to point 3
in the end, each ListView template is created from ObservableCollection<String> generated from one of the List<Data>
During the lifecycle, those lists might be renewed many times, which I would hope should recycle previous used memory? The list view rows/cells are created as Grids.
On small list views of up to tens of rows it works good and fast, not increasing memory use too much.
However, on large data sets, containing thousands of rows, even scrolling the ListView sometimes just crashes the app and memory increases dramatically with each portion of data.
So the question really Is, from your own experience, what would you recommend in troubleshooting and perhaps redesigning of the approach?
You should really look at the Xamarin Profiler
Xamarin Profiler
The Xamarin Profiler has a number of instruments available for
profiling Allocations, Cycles, and Time Profiler
There could be so many problems its impossible to know where to start, as for design once again its hard to know how to refactor your app because we don't know what you are trying to achieve. If you need to use lists you need to use them and there isn't much you can do about it.
However, you need to start from first principles and make sure you are doing only what you need to do, instantiating only what you need to instantiate, keeping your xaml and UI with the minimal amount of cyclic calculations as possible. Last of all making sure your view models and objects are going out of scope and being garbage collected

Performance degrades after navigating to some pages

i have this weird problem with my WinRT app (Windows Phone only). The app is made of multiple pages, it uses an animation to show a side menu which mimics the hamburger menu in W10M. The animation and app performance are great when the app first launches, but after navigating to some pages (say 3 or 4 pages) the app performance gets worst and worst. I don't have any code that is running in the background on the UI thread or any other thread.
Is there something about navigation in WinRT i am missing? It is really weird and i don't know what is causing it.
Here are some considerations that impact performance in XAML.
Depth of the visual tree. You can drag on two controls, but those controls represent several nested controls - things like borders, buttons, and panels. Running your app and looking at it with the Live XAML Tree viewer can give you a hint if a control is more complex than you want. Also, keep depth in mind when you build your UI. Favor simple controls like RelativePanel and standard, non-re-template control.
Construction versus loaded logic. It's not uncommon for developers not yet familiar with XAML to implement complex logic in inappropriate places. For example, you might, in the constructor of a sub-classed control, tell it to go get some data or test some expensive condition. Ideally, you will use Loaded of a control, or OnNavigatedTo of a Page if you have this type of logic, and use async if you have the option.
Data binding. Data binding is awesome but it is also expensive. You can use it in a few dozen places on your page an not likely to ever make a difference, but if you start to use it everywhere and for everything, it can be really expensive. The easiest remediation is to reduce the bindings in your page. Next, you can change your bindings from Mode=OneWay (which is the default) to Mode=OneTime wherever you can. Next, you can switch from {binding} to {x:bind} wherever possible. Remember, binding is not wrong, it's just expensive, so use it only when appropriate.
Too many records. If you have a repeater like a ListView or GridView then you might have too many items appearing at one time. This is a big deal, especially on load. It's rare that the real cost is fetching the data, it's typically rendering the data. If your item data template is complex, then your visual tree depth may be multiplied several times with each record. Loading fewer records at load and then showing more over time is one approach. Using x:Phase is another great approach. Simplifying your item templates is another approach. Minimizing data binding in your item templates can help. But, the best you can do is to run the diagnostics tool and look to see what's causing it. It might not be your ListView at all.
Unused Visual States. Developers are smart to use visual states. However, some states they define are for edge cases and show only in certain circumstances. The XAML for those views may never appear, so they mark their Visibility to Collapsed. This is okay. But if you go one more step and use x:DeferLoadingStrategy you can prevent the cost of that XAML parsing and rendering at startup. When the visual state reveals that XAML, it will automatically be realized by the platform. You're the winner, so is the user.
So, 5 helpful tips to help your pages load faster.
Odds are, your reason is going to be something else :)
ONE MORE THING
Are you allowing your pages to be removed from memory? Is it possible that in your implicit code in your code-behind you are subscribing to a static or global event? Maybe you need to unsubscribe in your OnNavigatedFrom override. Since the problem gets worse over time, it sounds like it might be a memory issue. Though, that is just a guess. It's a common C# slip up.
Best of luck

Efficiently creating many instances of a winrt metro control

I want to be able to create a few hundred instances of a winrt control (a search result control) in a C# project. The problem is that doing so takes too long (tenths of a second or worse) and must be done on the UI thread, creating stalls and delays in showing results.
For now I've bypassed the issue by pre-caching many instance of the control during startup. This approach works, but affects the startup time (profiling shows 40% of processor time near startup is spent caching these controls) and creates details to be managed, like the size of the cache.
I think the issue is that every time the control is instantiated redundant work, like re-parsing XAML, is done by the underlying framework. Maybe there's a way to avoid repeating this work? Maybe I can cheaply clone an existing control? Does anyone have ideas?
You could do the pre-caching in a parallel thread. Will make less of an impact on startup time on multicore processors
searchresult.memberwiseclone wil give you shallow copies. It might be faster, not sure
Could you use just one searchresult and fill it with the right data just before use? In that case there is no need to create a lot. Just use one as a re-usable container.
If the time is spent when adding the controls to the parent forms you could use
suspendlayout/resumelayout (this is win32)
setting parent to invisible and back to visible when you are done
Is there another way to do the same things faster? (competing control, 3d party etc)
Forenote: it's been awhile so Microsoft may have fixed the win8 app UI virtualization by now. I haven't checked.
What I ended up doing at the time was just hacking together my own UI virtualization to work around the issue. Basically: caching controls and re-using them to display the viewable data (using a binary search tree to efficiently query what can be seen). I wrote a blog post about it.

How to design a high performance grid with VS 2005(specifically C#)

I need to build a high performance winforms data grid using Visual Studio 2005, and I'm at a loss with where to start. I've build plenty of data grid applications, but none of those were very good when the data was constantly refreshing.
The grid is going to be roughly 100 rows by 40 columns, and each cell in the grid is going to update between 1 and 2 times a second(some cells possibly more). To me, this is the biggest drawback of the out of the box data grid, the repainting isn't very efficient.
Couple caveats
1) No third party vendors. This grid is backbone of all our applications, so while XCeed or Syncfusion or whatever might get us up and running faster, we'd slam into its limitations and be hosed. I'd rather put in the extra work up front, and have a grid that does exactly what we need.
2) I have access to Visual Studio 2008, so if it would be much better to start this in 2008, then I can do that. If its a tossup, I'd like to stick with 2005.
So whats the best approach here?
I would recommend the following approach if you have many cells that are updating at different rates. Rather than try to invalidate each cell each time the value changes you would be better off by limiting the refresh rate.
Have a timer that fires at a predefined rate, such as 4 times per second, and then each time it fires you repaint the cells that have changed since the last time around. You can then tweak the update rate in order to find the best compromise between performance and usability with some simple testing.
This has the advantage of not trying to update too often and so killing your CPU performance. It batches up changes between each refresh cycle and so two quick changes to a value that occur fractions of a second apart do not cause two refreshes when only the latest value is actually worth drawing.
Note this delayed drawing only applies to the rapid updates in value and does not apply to general drawing such as when the user moves the scroll bar. In that case you should draw as fast as the scroll events occur to give a nice smooth experience.
We use the Syncfusion grid control and from what I've seen it's pretty flexible if you take the time to modify it. I don't work with the control myself, one of my co-workers does all of the grid work but we've extended it to our needs pretty well including custom painting.
I know this isn't exactly answering your question, but it writing a control like this from scratch is going always going to be much more complicated than you anticipate, regardless of your anticipations. Since it'll be constantly updating I assume it's going to be databound which will be a chore in itself, especially to get it to be highly performant. Then there's debugging it.
Try the grid from DevExpress or ComponentOne. I know from experience that the built-in grids are never going to be fast enough for anything but the most trivial of applications.
I am planning to build a grid control to do the same as pass time, but still haven't got time. Most of the commercial grid controls have big memory foot print and update is typically an issue.
My tips would be (if you go custom control)
1. Extend a Control (not UserControl or something similar). It will give you speed, without losing much.
2. In my case I was targeting the grid to contain more data. Say a million row with some 20-100 odd columns. In such scenarios it usually makes more sense to draw it yourself. Do not try to represent each cell by some Control (like say Label, TextBox, etc). They eat up a lot of resources (window handles, memory, etc).
3. Go MVC.
The idea is simple: At any given time, you can display limited amount of data, due to screen size limitations, Human eye limitation, etc
So your viewport is very small even if you have gazillion rows and columns and the number of updates you have to do are no more than 5 per second to be any useful to read even if the data behind the grid id being updated gazillion times per second. Also remember even if the text/image to be displayed per cell is huge, the user is still limited by the cell size.
Caching styles (generic word to represent textsizes, fonts, Colors etc), also help in such scenario depending on how many of them you will be using in your grid.
There will be lot more work in getting some basic drawing (highlights, grid, boundaries, borders, etc) done to get various effects.
I don't recall exactly, but there was a c# .net grid on sourceforge, which can give you a good idea of how to start. That grid offered 2 options, VirtualGrid where the model data is not held by the grid making it very lightweight, and a Real grid (traditional) where the data storage is owned by the grid itself (mostly creating a duplicate, but depends on the application)
For a super-agile (in terms of updates), it might just be better to have a "VirtualGrid"
Just my thoughts

Categories