So I have a ListView with a UniformGrid of 16 rows and 32 columns as it's ItemsPanelTemplate. ItemsSource is bound to an ObservableCollection of objects that have two properties: IsSelected and Value. Each cell in the UniformGrid contains a TextBlock whose Text property is bound to the Value Property of its respective item. Below this construct, I have a ScrollBar whose value ranges from 0 to 255. Adjusting this ScrollBar changes the Value Property of the selected items in this grid.
Now that I've painted that picture, here is the problem. The issue is when I have many slots selected, and change the value of the ScrollBar, it updates all of the TextBlocks at once, causing visible lag. I scoured the internet for a solution to this problem, reading many articles on improving rendering performance and such. I have tried using Glyphs to try and increase the speed of text rendering, which showed improvement, but the lag was still painfully visible.
If I can somehow render the text only once per value change, and copy it to all other selected slots, I think this would improve performance. Is there a way to do this? If not, is there a different way I should be doing this kind of thing?
If not all of them are visible you could look at reducing your lag by looking into using VirtualizingStackPanel property.
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling"
http://miteshsureja.blogspot.com/2011/05/virtualizing-stack-panel-in-wpf.html
Additionally, if it's because of the speed at which a scrollbar can change value, and the draw of the UI just can't keep up....you could use a Timer that gets restarted anytime the scrollbar/slider changed event is called.
Once the timer elapses (lets say you pick 1 second) without being restarted by the change event, then it updates the value that the boxes are all binded to so that it only updates once the user stops moving the scrollbar/slider.
There does not seem to be a a way to easily copy the rendered text to other TextBlocks. The only way to increase render performance whilst maintaining immediate response was to switch to Glyphs. Will update answer if I find a way to render text once, and copy it to the remaining Glyphs.
Related
I've tried accessing rendersize, actualheight, height, nothing is providing height of all items inside my ItemsControl element - in fact the only property returning a value is ItemsControl.ActualHeight; however this is returning the same size as the parent StackPanel element, which is nested inside a grid.
Is there any way to calculate or pull the full height of an ItemsControl element with all Items generated/rendered? Currently if my window renders at 1920x1080 and I've got a ton of items in my ItemsControl - the ItemsControl actualHeight always matches the windows height; I need to be able to determine the full length of all my items and how it compares to the window size.
Thanks really appreciate your time and assistance!
ItemsControls are complicated entities, you see, there is progressive/incremental loading built in to those controls, it is part of a system called Virtualization, and it an extremely widespread across all UI systems, when you scroll down on BinGooglGo image results you get progressive loading for example.
Not all items inside the ItemSource are rendered at the same time, instead only what the user sees have a 'physical' form.
It is often for example that, A typical UWP ListView will only render the exact amount of items that fit into the current ViewPort (visible area) plus about 10-20 more items south and north of of the viewport in preparation of a scrolling action.
Edit:
But because i dont like leaving my answers not being solutions, i will showcase the following albeit Anti-Pattern :
Wrap your ItemsControl with a Scrollviewer, it will cause an immediate load of all of its contents.
I want a grid in my page to have a single column in portrait mode and have two columns in Landscape mode. Some of the content should move to the second column when the device is Landscape. I've tried to do this but couldn't.
I'm doing everything from code behind. Generating the grid, adding children etc. When Orientation changes, I destroy the current layout and create a new one. The problem with this approach is, any entered data will be gone. It's a huge code and not possible to put here. I want this layout change to happen automatically. So, any data that is entered is preserved after the orientation change.
Any help would be appreciated.
The trick is to have one grid that accommodates both states. You can use VisualStates to assign different Grid.Row, Grid.Column, Grid.RowSpan and Grid.ColumnSpan values to controls. This is done using Blend and is declarative in XAML. you give each state a name. In the code you detect size change of the window to trigger the different states using the VisualStateManager.
You can also do this without VisualStates. In that case in the event handler of the SizeChanged you have to set the appropriate values for all the controls yourself.
In Windows 10 UWP it got much simpler using RelativePanel. You can position controls in a more flexible way then with grids.
Martin
I have the following application:
I am developing a Windows Store app in which I need to show a big grid filled with buttons. The content of the buttons are some numbers and when I click any of them, I open a Popup with editor, where I edit those numbers. For that purpose I use a GridView, I put an ItemsWrapGrid as ItemsPanel. This makes the grid look exactly as I need it to look. I put the GridView inside a ScrollViewer, because I need to scroll the grid in both directions, since it has a lot of elements. Also I need to have the pinch-to-zoom effect that the ScrollViewer gives out of the box. I need to change the ItemsSource for that GridView when the user chooses different source in a ListView next to the GridView.
The problem:
Putting the GridView inside the ScrollViewer breaks the Virtualization inside and this has a major impact on my performance. When I switch the ItemsSource of the GridView, it takes more than 3-4 seconds for the rendering and during that time, the UI is frozen.
My question:
How can I keep the awesome stuff that the ScrollViewer gives me and also keep the virtualization? Because when I remove the ScrollViewer, changing between the ItemsSources happens almost instantly.
Any idea?
You'll be best off implementing virtualization yourself since you're trying to use the GridView far from the use cases it was designed for.
Put a Canvas in a ScrollViewer that does both pan and zoom and handle view change events on the ScrollViewer by laying out item containers inside and around the viewport. Avoid unnecessary changes too, so keep containers in place if they are to stay realized between view change events and recycle containers that are leaving the viewport neighborhood.
I have a ListBox that contains two columns - column one contains a Toggle Button, column two contains an Expander with multiple controls within it. If the expander is collapsed, the overall scrolling of the ListBox works fine. However, if the Expander is open and the expander contains a large quantity of items, the ListBox will scroll the entire row size, often not showing part of the expander list.
This would be similar to placing an image in the list box that is larger than the viewable area of the list box. In this case, if you click the scrollbar, you would want to "step" down the image, without it scrolling off the screen in one click.
Is there a setting for the ListBox that will allow the partial scrolling as I've described? My listBox is defined in a xaml, the controls are added via C# code.
Have you tried turning on smooth scrolling by setting ScrollViewer.CanContentScroll to false? This is what controls whether the ScrollViewer will scroll an item at a time, or smoothly with partial items available.
"ScrollViewer currently allows two scrolling modes: smooth
pixel-by-pixel scrolling (CanContentScroll = false) or discrete
item-by-item scrolling (CanContentScroll = true). Currently WPF
supports UI virtualization only when scrolling by item. Pixel-based
scrolling is also called 'physical scrolling' and item-based scrolling
is also called 'logical scrolling'."
(From this answer).
If you have a lot of items in your ListBox, this may not be an ideal solution, however, because it turns off Virtualization, and therefore may have a performance impact. Take a look at this answer to see more about smooth scrolling and virtualization. (One answer suggests a hack that allows for smooth scrolling and virtualization).
I have a question concerning listbox or something similar that could help me. I read lots of pictures from an json and I display them into a list box, I made the image as it’s could fit the page and I scroll them horizontally ,so that I can display them as an album of pictures.
The problem is when you scroll in a listbox, the scroll just keeps going it doesn’t stop, what I want to do is I can display only one picture each, and the scroll stops each time a display a picture.
Do you have any idea how can I do this? Thank you!
Have you looked at the RadSlideView from telerik?
RadSlideView is a unique control that allows you to navigate through a
sequence of items slide-by-slide. It works in data-bound mode only and
offers exceptional performance with smooth transitions among slides.
It may not be pretty but here's one solution -
Add a slider and use it instead of scroll-bar
Have just one image control
Set Slider's Minimum = 0 and Maximum = number of images
Set Slider's TickFrequency="1", IsMoveToPointEnabled="True" and IsSnapToTickEnabled="True"
Change your image when slider's value changes
Additionally, you can handle scroll events to ++ or -- the slider's value