I have a grid view that is populated with lot of items...each item has a Image in it. And when user scrolls down, some items become unrealized by virtualization. And, when user scrolls back to show them, those items start to update data, image source. The problem is that updating image source blocks the UI, and items in my grid are not showing until the image is loaded. This looks bad, and very choppy scrolling...
Here is the example what virtualization is doing in gridview:
My question is, how to set number of items that virtualization will make realized?
Use the CacheLength property of the virtualizing panel.
<ListView>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsStackPanel CacheLength="0" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
If cache length is in multiples of view port size. So if 3 items are visible in the window and cache length is 1, then you'll have 3 realized items before and 3 realized items after, (3+3+3 = 9). If cache length is 2, then 6+6+3 = 15, etc.
This works with GridView as well:
<GridView>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid CacheLength="0" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
Related
I have this combobox which is bound to a list of customers with around 5k entries
<ComboBox ItemsSource="{Binding Customers}" Margin="0 0 0 18"
DisplayMemberPath="DisplayMember"
SelectedValuePath="Id"
SelectedValue="{Binding CustomerId,Mode=OneWay}"
>
<ComboBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ComboBox.ItemsPanel>
</ComboBox>
I changed to virtualization and this helped in getting the list faster but when I added SelectedValue to bind to my viewmodel it got very very slow to load.
Is there any way to overcome this problem ?
Regards
5000 entries in a combobox is quite a burden on the system.
It is also a burden on a user. In general a combobox should not contain more than 10 (debatable) items.
In general I would make the user (or the system) do a pre-selection by adding a filter which decides what items should show in the combobox E.g., all names starting with "A" or, if that set is still too large, all names starting with "Ande".
I'm very new in WPF and I need some advise on how to create a view with many UIElements at the same time. What i want to do, is to view some kind of table with fixed width and height for each cell. In each cell could be a random number of textblocks with a different back and forecolor (see image).
Image for table-like view with many UiElements
That is what I have done so far... I created an usercontrol for the content of one cell which binds the items in an itemcontrol.
<ItemsControl ItemsSource="{Binding}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="1" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Background="{Binding Backcolor, Converter={StaticResource IntegerToBrushConverter}}" >
<Viewbox MaxHeight="20" >
<TextBlock TextWrapping="Wrap" Text="{Binding Caption}"
Foreground="{Binding Forecolor, Converter={StaticResource IntegerToBrushConverter}}"/>
</Viewbox>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
This usercontrol is also binded to an itemcontrol for representing the x-axis of my table.
<ItemsControl ItemsSource="{Binding}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:DayView DataContext="{Binding Days}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
And the same is done for the y-axis with an nice scrollviewer around. So, the problem is, that there are many many elements in the virtual tree. In my sample case there are over 60.000 elements listed in the tree. This results in a bad performance, when opening the view. The scrolling performance is quite okay, but he takes several seconds to open the view.
I've tried some things like the CacheMode and so on, but all of that doesnt effect the opening performance. Using a VirtualizingStackPanel results in bad scrolling performance. I even cant figure out what takes so long to build up the Ui. Seems that he need a lot of time to measure all UiElemtents, but Im not sure...
Are there tips to make such an UiElement rich view any faster? As I said, Im very new in WPF and that is only a performance test. We have such an Ui in Winforms, but there, the whole table was user painted. In WPF it is so easy to rebuild the Winforms design with stock content-controls that I only want to draw all for myself as a last resort.
Take a look here for a possible solution to your problem by using virtualization:
WPF Data Virtualization
Also if you want to go another way, there are commercial 3rd party WPF control libraries that handle virtualization with various degrees of success. To name a few: Xceed, Syncfusion, DevExpress and Telerik.
I even cant figure out what takes so long to build up the Ui.
Hoping you are using VS2015 (or something better), there are a few ways to get an answer to what is taking so long. Visual Studio has a live visual tree tool (Debug->Windows) where you can see the visual tree in real time and it might help you find and eliminate some of the UI elements you don't really need (like borders inside more borders, etc)
Second, you can run the Diagnostic tools (Alt+F2), choose CPU usage and that should generate a report where you can see where your program is spending the most time. Hopefully this will isolate the issue to certain methods that can be optimized afterwards.
Also, more detail about your problem would be welcome. What is the code that populates the ItemsSource do exactly?
I have a panel and I added it in a Window as ItemsPanel of an ItemsControl
<Grid x:Name="outerGrid" >
<ItemsControl ItemsSource="{Binding ImageSourcesCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<view:CustomPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
As you can see in this panel I show a series of images. Everything works all right, but now I want to access those images from inside the CustomPanel to change the Source to one of them.
If I access them as elements of base.Children I obtain a ContentPresenter, i.e.:
var element = base.Children[i]; //<- this is a ContentPresenter
So my question is: how can I get the Image?
One solution, since I know the position of the image, would be to get the element at that position. But I would prefer something else because it is not really clean and if I have other images moving around it can be a source of troubles.
Thanks!
I found out that if you just want to change the source of the Image (and this was my case), you can change the property Content of the ContentPresenter. Not sure how to access the Image though...
I have a string array like
string[] strngData = new string[] {"12","11","23","34"};
This string array length may be up to 4000. I need create a textbox for each string and loading all the text boxes inside a stackpanel within scrollviewer.
As the number of strings increases and number of textboxes increases resulting, the time to render the controls to UI is taking more time. for displaying 4000+ strings it is taking around 18+ secs.
Is there a way to improve the rendering time?
n place of stackpanel you may use ListView (which has inbuild deferred UI loading) with custom ItemTemplate and ItemsPanelTemplate:
<ListView Name="x" ItemsSource="..." HorizontalContentAlignment="Stretch" VirtualizingPanel.IsVirtualizing="True">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel HorizontalAlignment="Stretch" Orientation="Vertical"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Path=/}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
There are some key moments: you have to use VirtualizingStackPanel in ItemsPanel template in place of usual StackPanel; TextBox.Text binding path have to be equal to /(working with current item); I also test the example for ObservaleCollection so using of List may disallow you to edit items position, count, etc.
I took the standard Item GridView template and modified it a bit to fit my needs. I actually have changed very little of the template code.
I have a single group, and I have a lot of items in it (92 items). The listview does render some of them, but it only renders 12 of them. Why is that? How can I override that and make it display all of the items?
Here's a screenshot of me broken into the debugger as I'm setting the DefaultViewModel:
I add items to my listview like so (as I parse XML from a service):
DataSource.AddItem(new DataItem(... title, name, etc, DataSource.getGroup("gallery")));
Then in my DataSource class (this is exactly the same one as the sample, I just renamed it), I added this method:
public static void AddItem(DataItem item)
{
item.Group.Items.Add(item);
}
Here's what the XAML that renders this looks like (it's the same as the GridView template:
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="1,0,0,6">
<Button
AutomationProperties.Name="Group Title"
Content="{Binding Title}"
Click="Header_Click"
Style="{StaticResource TextButtonStyle}"/>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
I'd really appreciate any help.
Grid application template limits amount of items displayed in each group to 12 for reasons explained in the comment below:
public class SampleDataGroup : SampleDataCommon
{
...
public IEnumerable<SampleDataItem> TopItems
{
// Provides a subset of the full items collection to bind to from a GroupedItemsPage
// for two reasons: GridView will not virtualize large items collections, and it
// improves the user experience when browsing through groups with large numbers of
// items.
//
// A maximum of 12 items are displayed because it results in filled grid columns
// whether there are 1, 2, 3, 4, or 6 rows displayed
get { return this._items.Take(12); }
}
}