Performance Concepts: WPF TreeView - c#

So, I'm writing a JSON viewer in WPF (I know there are a few out there, but I want more out of them and I want to use it as both a learning opportunity and a personal project). Since it's JSON, I want it to be able to hold vast amounts of data. I'm displaying everything in a TreeView, but the UX is starting to fall over when I get a lot of data. Not even a TON -- we're talking loading 89k of JSON here, though that 89k represents a little over 4000 nodes right now.
Ideally, I'd like to be able to display it all in a tree pre-expanded the first time the user gets there. However, I'm unhappy with how WPF is handling that many nodes in a TreeView and I'm not sure what to do about it.
I started with the VirtualizingStackPanel (IsVirtualized and VirtualizationMode="Recycling"). Those did a pretty good job of things, but it made scrolling wonky -- since new data comes in pre-expanded (via a style right now that sets each TreeViewItem.IsExpanded to true), the scrollbar tends to jump up and down while the user scrolls down in the window. On the bright side, the window loads up more-or-less instantly.
I know I don't have code in this post, but my question is more conceptual: what are some mitigating strategies I can use to fix this? Here's what I've come up with so far:
Load everything collapsed: Don't bother pre-expanding stuff. This is the route I am least enthusiastic about. Sure, it will help with particularly large data sets, but the small data sets will require manual expansion, and I'm suspecting that's the more common case.
Load everything collapsed if there are more than N nodes: This could work from a UX standpoint, though the value of N would be fairly arbitrary. I've seen the TreeView start to stutter after 790 nodes, so that apparently is a problem point; I'd have to do some more research into exactly where the breakpoint would be.
Lazy loading: Load nodes on-demand. Nodes would load very quickly -- I'm playing with JSON in memory, after all -- but it suffers from exactly the same problem as the first idea, loading everything collapsed.
Expand only the first node: Seems rather arbitrary, really. Plus, if the first node was particularly large, we're back to square one.
Expand everything in the background and show a loading screen or something: Would that even work? Can I push a UI thread to a background thread, or affect the UI on a background thread while I show a spinner or something? Never tried it -- my development career has always run into "This is the UI thread. Never hold it up." It never occurred to me that you could even have two UI threads. Does anyone know if you can?
Hide the control, load data into it, and show it when loading is done: Two problems with this. First, I'd have to figure out how I know when loading is done (I'm using binding here, so I'm not going through a method whose exit I can detect). Second, would it make any difference, or would it fall over as soon as it's un-hidden and starts rendering? That one I can look into.
Give up and take a vacation in the Carribbean: Because why not?

Related

Multiple DataGridView updates make my app unresponsive

I have FlowLayoutPanel with multiple small DataGridView controls.
I feed the data sources of the controls in background thread. This IS NOT the source of the problem. The grids have to be updated in "real time", so I update them at least once a second, for testing I set 100ms per update. It works, however UX is very choppy and unresponsive. When I try to move controls on screen the movement is not smooth.
When I disable a single line in code:
control.DataSource = items;
it runs perfectly smooth with no hickups, but of course I have no data in grids. I have data read from database, processed in code, only not displayed. All those operations don't take much CPU or IO time, my machine is almost idle.
What can I do to stop grid updates from blocking UI? Invoke or BeginInvoke does not help. The same thread, the same message loop. Is there a way for non-blocking update?
Increasing update interval doesn't help much - the hickup occurs less often, but it ALWAYS occurs which is very disturbing when a user tries to move a control from one window to another. The feature of draggable controls is crucial to the app. Is there something to be done to improve UX except creating own, low-level, optimized DGV?
No, I won't paste my code here, it's too huge and most of it is completely irrelevant to the problem. The problem is simple. I got data ready in memory DataSet objects. All I need is to pass it to DataGridView controls without UI hickups on "dgv.DataSource = myDataTable" operations.

What are Parking Windows in Winforms

This is a follow up question to this answer https://stackoverflow.com/a/20584601/2530848.
I was under the impression that Control class doesn't implement finailzer which is true indeed, so leaked controls are leaked forever, not cleaned up during finalization.
Hans Passant gives some hint in comments section saying that it does, and some keyword ParkingWindow. I googled with that keyword, can't find any helpful resource about that.
Finally I found a class named ParkingWindow in System.Windows.Forms.Application.ParkingWindow through decompiler, I can't get to understand what is being done with that.
It looks like unparented windows will be parented to this parkingwindow and destroyed later at some point but not sure.
Question is what exactly is ParkingWindow and What it is used for?
Edit: How that is related to Control's Finalization or cleanup?
and destroyed later at some point but not sure
That "not sure" is the crux of the problem. This goes wrong very often with the window not getting destroyed at all.
Shawn Farka's blog post explains the original intent of the Parking Window well. The expense of having to re-create the child windows was certainly on top of the list. Not the only concern though, some types of child windows are very difficult to re-create accurately. A TreeView is a good example, there's rather a lot of runtime state associate with it. To do it accurately, you'd have to record the collapse state of every node. That's painful and Winforms does not in fact do this. When you re-assign, say, the CheckBoxes or StateImageList properties then you'll see this going wrong.
All and all, it is a nice trick but they went overboard with it. A child control doesn't just (temporarily) end up on the Parking Window when the parent window gets recreated, it also is moved there when:
you set its Parent property to null
you use the parent's Controls collection's Remove/At() method
you use the parent's Controls collection's Clear() method
Particularly the last two bullets are almost always deadly in a typical Winforms program. They tend to be used when the programmer dynamically adds and removes controls at runtime. Problem is, the control is re-hosted on the Parking Window but the programmer just forgets them there, losing the reference to the control. And they will live there forever. Until the user terminates the program because it turns into slow molasses from having thousands of windows created. Or the program crashes with "Error creating window handle". Which occurs when Windows gets sulky after the program has created 10,000 windows.
Instead, it is required to call the Dispose() method of the control. Very unusual in .NET in general, calling Dispose() is always optional. Not in the case of the Control class, the Parking Window keeps a reference on the control and thus prevents the finalizer from running.
This is covered on this article by Shawn Burke from MS: Windows Forms Parking Window.
One of our goals with Windows Forms was try to smooth out as much of
the oddity of Win32 as we could. And one of the principal oddities is
that of window handle (HWND) management and lifetime. We certainly
didn't want the average user to need to worry about this stuff. In
most cases, it was pretty easy. You just gather up all of the state,
and then when you actually need to show the window, you do the
creation on demand, then you drive your state off the HWND instead of
your internal members.
Well, this doesn't always work so well. See, there are certain
properties of Win32 windows that you can't change once the window is
created. Like the style of the border, for example. So to allow a
user to change the border style after the window has been created, you
need to recreate the handle. Which means you need to not only pull
all of the state out you want out of the existing one, but you need to
recreate it and push it back in. Okay, that's not too hard.
But what about the children? Oh, fiddlesticks. The kids.
If the window you're modifying the border on has children, destroying
its handle will destroy the handles of all of its children as well.
Then you need to recreate them, which is very expensive. And
expensive is bad.
Enter the Parking Window. The Parking Window was our solution to this
problem. It was somewhere that you could "park" HWNDs until you have
a fitting parent for them. Think of it as Window Handle Foster Care,
but invisible.
So in the case of a handle-recreate, we'd check to see if there were
any children. If there were, we'd (if needed) create the Parking
Window, parent the children to that, recreate the parent's handle,
then move them back over. Worked pretty well, though managing the
lifetime of the Parking Window did cause some problems...

how to open winform faster?

i have a c# application and there are a lot of forms with controls.
And every time when i run my application, forms which have many controls open slow.
So is there any way to make it open faster?
As you can see from the comments, there isn't one universal "make things faster" technique. You need to find the bottleneck and fix it. Here are some pointers:
Are all your controls on all your forms added statically in the designer, or added dynamically at runtime based on environment/user details/loaded dynamically via reflection? These can significantly slow down UI load time.
Do you have hundreds of controls on a single form? If so, consider splitting your forms to smaller chunks.
Do you have complex logic or data access during your Form_Load events? This can also slow down UI responsiveness. Consider starting the application "clean", and then loading the data asynchronously.
Use a profiler! Find a good, simple profiler to see where, exactly, you're spending your time. You'll often be surprised at what actually takes time. Use a trial version of a good, established profiler like dotTrace or Ants, and consider buying it for the future.
Instead of making it load faster, I would recommend you to give better user experience to your user.
First, load a Splash View (with loading progress) first. On next thread running in background, load your View with a lot of controls. When your view loaded completely, hide the Splash View and show your View.
In case you do something timeconsuming code with the controls in form constructor or while loading form you can write this.SuspendLayout(); before that code and this.ResumeLayout(); after that code. That prevents several time-killing layout operations.
Considering the information in question provided I wolud say:
Devide controls in possible groups (It's practically impossible that user needs all controls at the same time) and put them on separate Tabs of tab control.
Automatically (statially) load only controls on fisrt Tab, for others load them dinamically.
In this case, if the user doesn't need certain functonality will never switch to the Tab that contains it, so the controls of that functionality that user doesn't need will not be loaded, which will provided overall faster load time.
If there is a data that should be pushed on the controls, load it in async way where it's possible,
Hope this helps.
I have had a similar problem, but with many more controls than yours.
Considering that you have a relatively small set of controls, I think the culprit is the data access layer slowing down everything. (The loading of that grids and combos for example)
A simple action that can tell you many things is to move your data access to the form_shown event.
In Visual Studios (under the Solution Explorer), you can right click your solution/solution name and select properties at the bottom of the list. If you select "Configuration Properties," then go under configuration, you can select "Release" instead of "Debug." This will shave time off loading significantly.
Also, it is wise to avoid using "Thread.Sleep" in your code. This method is often used and mostly for poor code writers. About 10% of it is viable for particular circumstances, but I would avoid it at all cost.
Best way is to separate your solution to many layers
YourAppUI contains forms
YourApp.Controls contains controls
YourApp.BLL contains business logic
YourApp.DAL contains data access layer

GUI is non responsive while updating grid having 80 columns during heavy update

I am having an application which is for securities trading in stock exchange. It has real time market feed from one of the vendors. We are processing market data on worker thread(s) and while updating main GUI we are marshaling this data to GUI thread.
Let me make this more clear, there is an ultragrid (third party gridview) having 80 columns, we have around 40 rows with same security that must be updated as and when there is fluctuation in market data. We are able to handle market frequency of 10 messages/sec/security. But beyond that we are unable to handle. GUI becomes non-responsive when frequency increases to 25-30 msgs/sec/security. We have followed best practices while designing and implementation but still we can not handle high freq. We are performing all non-GUI specific work on worker/back-ground threads, but still facing GUI hang. Please help in suggesting me any out of the box solution to tackle this problem. Here I can not put code snippet due to security reasons.
Switch your grid component to something that can double buffer and multithread (I expect most data will remain static around updates), or roll your own. Rolling your own sounds unavoidable: this kind of heavy update activity isn't the most common use case for grid controls. I'd start looking for grid controls with open source code you can modify, at e.g. http://www.codeproject.com or http://www.codeplex.com. What to pick depends on your other requirements, alas.
The key thing here is to virtualise everything - the only interaction between your data model and the grid should be when the relevant cells need to be painted. In order to do this you will need to use a grid that supports this kind of virtualisation (I've used a Syncfusion grid to do this before, see example here).
You will also want to batch the updates to your data model so that you don't block the GUI thread too frequently. Have a look at this question and answer.

Multiple Forms and a Single Update,Will it work?

I need to make an application in .NET CF with different/single forms with a lot of drawing/animation on each forms.I would prefer to have a single update[my own for state management and so on] function so that i can manage the different states, so that my [J2ME Gaming Code] will work without much changes.I have came to some possible scenarios. Which of the one will be perfect?
Have a single form and add/delete the controls manually , then use any of the gamelooping tricks.
Create different forms with controls and call update and application.doEvents() in the main thread.[ while(isAppRunning){ UPDATE() Application.DoEvents() }
Create a update - paint loop on each of the form as required.
Any other ideas.
Please give me suggestion regarding this
If its a game then i'd drop most of the forms and work with the bare essentials, work off a bitmap if possible and render that by either overriding the main form's paint method or a control that resides within it (perhaps a panel). That will give you better performance.
The main issue is that the compact framework isn't really designed for a lot of UI fun you don't get double-buffering for free like in full framework, proper transparency is a bitch to do with WinForm controls and if you hold onto to the UI thread for a little too long you'll get serious rendering glitches. Hell you might even get those if you do too much on background threads! :O
You're never going to get optimal performance from explicitly calling Application.DoEvents, my rule of thumb is to only use that when trouble-shooting or writing little hacks in the UI.
It might be worth sticking the game on a background thread and then calling .Invoke on the control to marshal back to the main UI thread to update your display leaving the UI with plenty of time to respond while also handling user input.
User input is another reason I avoid normal winform controls, as mobile devices generally don't have many keys it's very useful to be able to remap them so I generally avoid things like TextBoxes that have preset key events/responses.
I'd also avoid using different forms as showing a new form can provide a subtle pause, I generally swap out controls to a main form to avoid this issue when writing business software.
At the end of the day it's probably worth experimenting with various techniques to see what works out for the best. Also see if you can get any tips from people who develop games on CF as I generally only do business software.
HTH!

Categories