I have performance issue with my wpf application. I am displaying a form with many textboxes (like 130 or so). It is a software where user can configure many states in three stages of a distiller machine. The form consists of three sections (stages), each can have different number of states and some fixed amount of properties to setup. Each state gives user option to set 6 values(via textbox).
So if a stage consists of for example 7 states, then it has 7x6 + 5 (fixed amount) = 47 textboxes. So the 3 stages can show 141 textboxes (it will be less because only two stages can be visible rest can be scrolled down).
https://pasteboard.co/I8LiVxG.png
To display the states for each stage I am using ItemsControl with ObservableCollection binding. This is a bottleneck in VS performance profiler as the application spends too much time in layout (orange color).
When I swap the ItemsControl with StackPanel and fixed amount of states, the problem is gone.
https://pasteboard.co/I8Lhu37.png
Of course the UI is a bit more complex, there is a listbox with distiller processes and each process is displayed in detail with stages and states. I have also viewmodels and bindings, the states count can be changed runtime so there is ObservableCollection bound to the ItemsControl. None of this is causing the issue, i tried to turn off most of the mvvm code that resets the values or recreates collection of states.
<ItemsControl Grid.Row="2" ItemsSource="{Binding Cuts}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:RunConfigControl DataContext="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
In the code above RunConfigControl is just a Grid with 6 textboxes and labels. Cuts is the name of the ObservableCollection.
What is the difference when I use just a fixed amount of controls in StackPanel and when I use ItemsControl with collection. There is also StackPanel when i look at the visual tree.
Also I know that the controls are rendering when not visible (I am not using virtualization) but there are not many states (between 2-10) and the number of stages is always 3. Also all the states need to be visible I don't need to show 3 states and scroll for 7 others. Also I see two and half stage on the screen so the one half of last stage rendering despite not visible should not be the problem.
Thanks for any kind of help
I would use an editable DataGrid. This could be bound to your observable collection. The benefit is that a textbox is only create when editing, otherwise a textblock is used. You can style your grid to look like your picture. You can also set the cell to edit mode on mouse down so only a single click is needed to enter a textbox (cell).
Here is an example. You could get the look you want by hiding the headers, and adding some cell padding.
Related
I have a StackPanel of Datagrids that contain data about various things. A user should be able to click on one of those datagrids and that datagrid should expand and take the place of the four datagrids on the screen. Clicking on the expanded grid should return the screen back to the previous display of four data grids.
I have tried replacing the top grid in the backend (I don't think this is a violation of MVVM since it is dealing purely with the display, but I could be wrong) with the selected grid, which doesn't seem to work. I have also tried hiding the grids to see if that would work. I found several topics here and elsewhere talking about moving columns and/or rows around at runtime, but nothing about moving an entire datagrid at runtime.
I would suggest building your UI view as a grid with column/row sizes bound to match their content, and use a backend property to determine whether the various datagrids should be Visible or Collapsed as a result of your clicking. Then the UI will adapt to fit the scenario you want.
Another alternative is to have a couple of views which have the explicit arrangement of controls you want, then have an outer ContentControl whose Content property is changed to one or the other as a result of the clicks.
I'd favour the former though for simplicity if feasible in your layout.
I have a ListView with a GridView in my C# WPF application. The ItemsSource is bound to a ListCollectionView created on the ViewModel from an ObservableCollection<MyClass>. I use the ListCollectionView for dynamic sorting, filtering and grouping, all of which can be adjusted or turned on/off from the View.
When I alter the filter or turn the grouping on/off, all of the visual list view items are recreated, which causes the UI to freeze for about a second. Since I have about 250 items displayed and there are about 10 columns (some of which have cell templates with a progressbar), this comes as no surprise.
Now, I know that the obvious answer is to enable virtualization. This however, brings some undesirable effects, such as scrolling becoming jerky or the scroll-bar changing its size as you scroll (this happens with grouping on, since the groups vary in height and so the virtualizing stack panel can not calculate the total height properly at first).
What I would like to do is to have the ListView keep a visual element for every item in the raw list (un-filtered and un-sorted, i.e. the ObservableCollection<MyClass>) and then only add to or remove from the visual tree depending on the changes in the ListCollectionView.
I hope this solution should boost my app's performance, since I rarely change the raw list, but I often alter filtering, sorting and grouping.
Do I need to create a custom control inheriting from ListView (or GridView) to do this, or is there another way?
Try to use DeferRefresh, this delay automatic refresh until the defer cycle is existed. See if that helps.
CollectionView view = (CollectionView)CollectionViewSource.GetDefaultView(SomeListView.ItemsSource);
using (view.DeferRefresh())
{
view.GroupDescriptions.Clear();
view.GroupDescriptions.Add(new PropertyGroupDescription("Country"));
view.GroupDescriptions.Add(new PropertyGroupDescription("Active"));
}
http://blogs.msdn.com/b/matt/archive/2008/08/28/collectionview-deferrefresh-my-new-best-friend.aspx
I have some trouble with ListView where the ItemsSource can be very important (over 5'000 items).
My application is that of a Chat Application consisting of two ListViews.
One on the left, the thread ListView showing a list of active thread
(conversation)
One on the right, the conversation ListView showing all messages exchanged.
I am using the DataTemplatepattern so that each item of my conversation ListView is customized as follow :
A chat Bubble using Coding4Fun package : http://www.geekchamp.com/articles/getting-started-with-the-coding4fun-toolkit-windows-phone-chatbubble-control
Each Chat Bubble has two TextBlock (one for the message content, the other for the timestamp).
Later, I intend to add pictures to this messages.
When user clicks on a conversation from the left-panel ListView, the main conversation ListView is loaded with the corresponding conversation (observable) collection.
If that collection is particularly big (in one case, I have more than 10'000 messages), the conversation ListView does show the content, but as soon as a switch to another thread and back to the previous, the content does not show anymore, although it's here, it's loaded. Starting to scroll, makes the ListView flickering and the content, therefore, is visible but severly flickering. If I stop scrolling, no content is showed, showing an empty list.
Further tests showed that this problem occurs only with large collection in concordance of usage of ScrollIntoView() method: indeed, I whish to show the bottom of my conversation ListView each time a user clicks on a thread so that he can read the last messages instead of the oldes, therefore saving him to have to scroll all the way to the bottom, each time.
I confirmed this issue by commenting out the line where I make the ListView to scroll to the bottom. The flickering problem is gone.
Finally, as I wrote my question, I found a stackoverflow question that seems to be my case: Windows Store universal app - ListView oddity
Unfortunately, the solution is not very clear. How can I solve my issue ? How should I use VirtualizingStackPanel/>inside a ListView that uses alread <ListView.ItemContainerStyle>, ListView.ItemTemplate>and <DataTemplate> ?
The solution to my flickering problem and how to implement UI Virtualization (normaly introduced in Windows 8.1) as described here https://www.microsoftpressstore.com/articles/article.aspx?p=2216995&seqNum=4 is as follow :
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
To be placed within a ListView scope !
Orientation must be defined ( Vertical | Horizontal ) otherwise a Critial Failure occurs !
UI Virtualization enhance large GridViews and ListViews so that huge amount data can be effeciently loaded without slowing down the UI nore blocking it for too long.
Honnestly the answer to your problem would be to redesign your application.
Never should there be so many items in a listview. You need to filter out some results
Example : Sort the question names /types/ etc and only show the corresponding (such as tags in Stack Overflow)
Only show the last lines of the conversation when you load it and allow the user to load more (like facebook's messenger)
Take a look at this C# listview maximum number of rows
As the answer says. The amount of items in your listview should be limited by common sense. 5k items in one listview is an incredibly high amount for a user to scroll through.
I am assuming your bubbles are in some kind of list or array. You can use Linq to get what you want. Take a look at this LINQ query to select top five
I have a MVVM trading application.
MainView has two tab controls - left one displays a collection of "workspaces" and the right one displays dynamic data display charts.
When I create the first "chartviewmodel" the correct chart appears in the right tab control as expected.
When I then create another "chartviewmodel" with different data that should result in a different chart, that's not what happens. The second tab item is a duplicate of the first from a visual standpoint. The tab items are contained in a collection of items called: "chartspaces" and in debug mode I can see each viewmodel and indeed each has different values.
Also, in debug mode I put a breakpoint on the "Initialize()" method of the view and when the first chartviewmodel is created, that method indeed gets called. When I then create the second chartviewmodel, the "Initialize()" method is not called, so in fact another view is not getting created...but I can't figure out why.
My view/viewmodel's are tied together via DataTemplate with x:Shared="False" (tried it with and without this parameter). I've traced through the constructor of the chartviewmodel to ensure it was not getting any errors and it is not.
On the left-most tab control, I can create multiple tradeviewmodel and each results in a different view... in other words it is behaving as expected.
My XAML for the right tab control is essentially the same as for the left one with the exception of the "workspace" collection (left uses "workspaces" right uses "chartspaces" so I'm at a loss as to what might be wrong or how to diagnose this problem further.
The datatemplate looks like:
<DataTemplate x:Shared="False" DataType="{x:Type vm:ModelOptionChainViewModel}">
<vw:DDDRiskChart />
</DataTemplate>
In further experimenting, I put the tab items on the left side instead and found the same problem, but if I selected a non-Dynamic Data Display tab item, then one of the DDD charts, they display correctly. So, before I selected a DDD chart I had to display a non-DDD chart, then the DDD chart for it to display.
So, moving the tab items back to the right tab control, I put the two DDD charts in, then put in a non-DDD chart (a DataVisualization chart). I found the same behavior...if I selected the non-DDD chart and then the DDD chart, it displays correctly. If I just alternate between the two DDD charts, they will both display the same graph! Is that not weird?
So, for any of you who care...the problem is actually associated with the TabControl behavior.
Irv Krivyakov has an excellent Code Project with description (link:
http://www.codeproject.com/Articles/460989/WPF-TabControl-Turning-Off-Tab-Virtualization )
that describes the problem AND provides a TabContent behavior class that eliminates the problem. The crux of the problem has to do with virtualization within TabControl. Rather than repeat his explanation, please see the above link. Also, see:
DataTemplate x:Shared=false has no impact on the view
especially the last post on that thread as it discusses TabControl and DataTemplate behaviors.
My fix was:
use Irv Krivyakov's TabContent behavior and my TabControl now looks like:
<DataTemplate x:Key="ChartspacesTemplate">
<TabControl
Name="chartTab"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
behaviours:TabContent.IsCached="True" // THIS IS THE FIX!!
ItemTemplate="{StaticResource ChartTabItemTemplate}"
Margin="4"
/>
Note: the one line change. Now when I switch tabs the correct data shows.
In my WPF application, I've got a screen with a tab control. Five of these tabs contain datagrids which need to display a large number of rows (at least 5000). The tables are bound to ObservableCollections of Part objects. Each row displays around 20 points of part data. My problem is that, after the user enters the information they require and generate the data, clicking on a tab causes the application to hang for 30-60 seconds. After this the datagrid finally loads, and with the right virtualization settings, they perform at an acceptable rate (not exactly fast, but not too slow). If I disable virtualization, the program uses up way too much memory, and the loading time isn't really affected.
The most offensive tables consist of about half a dozen template columns. Each template contains controls inside a stackpanel or a grid; basically each row is split into two, like a double-row. This layout is a requirement, and paging is probably not something that the customer is willing to accept.
This is the most important screen in my application and I'm pretty much at a loss about making this work. Is there anything I can do to speed up this process? Perhaps ObservableCollection is the wrong choice?
Can you please provide more insights...
Can you check how much time is spent in "generating" the 5 collections of 5000 rows each? (this is what I assume you are saying)
With virtulaization "on" what is the UI loading time "after" we assign the collection to the items source?
What happen if you bind "ItemsSource" to the respective datagrid only when the tabItem is actually Visible \ Selected?
Do you datagrids have default sort member path? Grouping? Filter Paths?
These are a few things I would target to start on the issue.