ItemsControl rendering slowly - wpf

I am using an ItemsControl for showing alist of items and itrs xaml is like
<ItemsControl ItemsSource="{Binding ShelfItemsCollection}" Name="shelfGridView" Margin="5" >
<ItemsControl.ItemTemplate>
<DataTemplate>
<Stackpanel>
<Image Width="150" Height="200" Stretch="Fill" Source="{Binding CoverImage}" ></Image>
+
some other infos
</Stackpanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
The problem i am facing is i had almost 100 items in list and i am doing some filtering operations on the list based on some properties and limit the results to a lesser no ( say 20 items at a time)for doing this filtering it took a lot of time to refresh and load the list view .
This is the code i used for filtering
ICollectionView dataView = CollectionViewSource.GetDefaultView(shelfGridView.ItemsSource);
dataView.Filter = CloudFilter;
dataView.Refresh();
private bool CloudFilter(object item)
{
MyObject lib = item as MyObject;
return lib.Property !=valuetofilter;
}
Is any way to improve the perfomance or any specific reason for slow rendering ?

ItemsControl doesn't support UI virtualization out of the box. Either use ListBox or make ItemsControl UI virtualized.
You can enable UI virtualization on ItemsControl by following some steps :
Set VirtualizingStackPanel.IsVirtualizing="True" on ItemsControl.
Set ItemsPanel to be VirtualizingStackPanel.
Override ControlTemplate of ItemsControl and wrap ItemsPresenter inside ScrollViewer.
Set ScrollViewer.CanContentScroll="True" on ItemsControl.
Details for the above proposal can be found here.
Moreover, you are setting ItemsSource directly to SourceCollection i.e. ShelfItemsCollection and later filtering it by getting defualtView created underneath for that collection. Binding directly with sourceCollection will force ItemsControl(non-Virtualized ofcourse) to generate 100 containers to host your underlying objects.
Instead you should create ICollectionView with filter predicate set on it and bind ItemsSource to that instance. May be you can also create CollectionViewSource and bind with it. If you bind with filtered instance, it will generate only 20 containers (non-virtualized ItemsControl).
Ofcourse, enabling UI virtualization on ItemsControl, will generate containers for only visible UI items on GUI.

Related

Why ItemTemplate will make items disappear for ListView?

I was solving Windows Phone 8.1 ListView wobbling problem and had code like below, however, once I add the ItemTemplate, the contents of the List cannot be seen, I'm wondering why and how to fix the problem.
<ListView
Grid.Row="1"
x:Name="ListViewEvents"
Loaded="OnListViewEventsLoaded"
ItemsSource="{Binding xx}"
ItemTemplateSelector="{StaticResource xx}"
ItemContainerStyle="{StaticResource xx}"
IsItemClickEnabled="True">
<ListView.ItemTemplate >
<DataTemplate >
<Grid Width="{Binding ActualWidth, ElementName=EventsListGrid}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Your Width binding is trying to read the ActualWidth property of an element in your XAML named EventsListGrid, but there's no such element in the sample code you've provided. As such, the binding engine is unable to set the Width property on your grid, most likely setting it to some unset/NaN value. At least I can confirm this when setting up a similar case as the one you provided and inspecting in Snoop the ListViewItem containers generated for each item in the test collection bound to the ListView. Perhaps you want to set the element name to ListViewEvents in this case or some other parent element not shown in the example?

What standard WPF control should I use?

I am trying the master-detail presentation in my app: when an item in a listbox is selected, its details are displayed in an adjacent control.
This control will have a list of measurements such as height, width, weight, etc. It will also have some small graphics such as a green or red dot or a medium sized image. It will also have some rich text.
Which STANDARD WPF control should I use to contain all these elements. I am thinking of using a listbox but wonder if there are better controls to use.
My main consideration is ease of coding, then possibly efficiency of the code.
Thanks.
A listbox indicates a list of items that can be tailored using a DataTemplate for appearence. In this case you are showing the details of a selected item. I would actually use a container such as a Grid nested in your current UI and have a set of stackpanel including the details of the selected item.
<Grid>
<StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock>Detail1</TextBlock>
<TextBox></TextBox>
</StackPanel>
<StackPanel Orientation="Vertical">
<TextBlock>Detail2</TextBlock>
<TextBox></TextBox>
</StackPanel>
</StackPanel>
</Grid>
This is only one suggestion but the point is to use a container and use a set of controls in the containers - textblock,textbox,checkboxes(boolean details), etc... this will allow you to use any control type necessary to represent the specific data field of the selected item.
You don't want to use a listbox unless you have a collection of similar items, and you want one or more items to be 'selected' at some point. It sounds like that is not what you want for the details part.
You do have a collection, which is shown in your master list. You should bind the SelectedItem in your master list to a property in your viewmodel. Then you can bind that same property to the details section of your UI. When the selection in the master list changes, your details UI will automatically update to reflect the changes.
<ListBox x:Name="masterList" ItemsSource="{Binding MyItems}" SelectedItem="{Binding MySelectedItem, Mode=TwoWay}"></ListBox>
<UserControl x:Name="detailsControl" DataContext="{Binding MySelectedItem}"> </UserControl >

If you were going to build an org chart builder in Silverlight, what base class would you use for creating the boxes of the chart?

For this question, let us assume that we will want to show the face of the employee, title, department, and whether they like PiƱa coladas/getting caught in the rain.
Perhaps it might look something like the following:
http://www.edrawsoft.com/images/examples/Photo-Org-Chart-Full.png
Would you use a...
System.Windows.Control.UserControl?
FrameworkElement?
UIElement?
Canvas
Why? As always, thank you for your advise! I greatly appreciate it!
If I had to create a org chart control with advanced layout I would probably derive from Control, and create a "real" templated control in a similar manner as e.g. the TreeView control. This is probably the most advanced route to create a new control, but also the most powerful.
You may also be able to modify the control template of a TreeView, and make it grow downwards from the center instead of left and down from the upper left corner, but it will probably be difficult or impossible to customize the layout of the various levels as the TreeViewItem doesn't carry any extra information to describe the layout of a particular node.
In fact I did recently some experiments modifying the TreeView control template, but I stumbled upon something I didn't understand. Luckily I figured out what I did wrong, and you can see how it is possible to change the orientation of TreeView child items from vertical to horizontal in my question here on Stack Overflow.
I've seen a website that uses TreeViewItem and ControlTemplates, but I can't find it at the moment, I think it was on CodeProject.
Another idea I was playing with recently is use 2 usercontrols, itemcontrols and stackpanels.
Here's an example of a an OrgBar rectangle with text under it and it renders it's children in OrgGroup control by setting the ItemSource to it's children collection recursively. You can put the root orgbar on a canvas and play around with paths for the arrows. I tried to point out the basics but if you need more I can fill in the blanks.
Public Class OrgBarDataNode
Public Property BarColor as New SolidColorBrush(Colors.Red)
Public Property BarName As String
Public Property Children as New ObservableCollection(Of OrgBarDataNode)
End Class
Class MainPage
...
Public Sub Loaded
Dim Root as New OrgBarDataNode With {.BarName = "Root"}
Dim Child1 as New OrgBarDataNode With {.Barname = "Child1"}
Root.Children.Add(Child1)
LayoutRoot.Children.Add(Root)
End Sub
...
End Class
<UserControl x:Class="OrgBar">
<Grid>
<StackPanel ToolTipService.ToolTip="{Binding BarName}" Cursor="Hand">
<Rectangle Fill="{Binding BarColor}" Style="{StaticResource RecStyle}"/>
<TextBlock Text="{Binding BarName}" HorizontalAlignment="Center"
Margin="0,10,0,0" />
<local:OrgGroup Margin="0,20" HorizontalAlignment="Center"
DataContext="{Binding Children}" />
</StackPanel>
</Grid>
</UserControl>
<UserControl x:Class="OrgGroup">
<Grid>
<!-- this {Binding} to nothing means bind to DataContext}-->
<ItemsControl ItemsSource="{Binding}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:OrgBar Style="{StaticResource OrgBarStyle}"
DataContext="{Binding}" />
<!-- this {Binding} refers to the the child node this time} -->
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</UserControl>
That's essentially a tree structure, so like Paully suggested, I would start with a TreeView (Silverlight Toolkit) and customize the control template and treeview itself.

WPF creating dynamic rows using MVVM pattern

I want to load my WPF UserControl with dynamic rows. My scenario is as follows.
1. When the UserControl gets loaded, I will populate my List<string> object with some values which I will get from a database.
2. I need to create equal number of rows in my UserControl which matches the number of items in the List<string> object. The display will look something like below
Column 1 is a Label Control and Column 2 will be a TextBlock control
Label 1: Item 1 (This is the value from the List<string> object)
Label 2: Item 2
Label 3: Item 3
I know how to create rows dynamically but my problem is how do I do this when I'm using the MVVM pattern.
Note: I'm using the MVVM toolkit from CodePlex.
Thanks,
Jithu
Set the MVVM object you have as the dataContext of your UserControl, I hope the object has a Collection property in it. Then create an ItemsControl more like below
It is not clear from your description that where is really the Label and Item comes from your ViewModel. The below code will create Rows dynamically as many as your Collection.Count.
<ItemsControl ItemsSource="{Binding YourStringCollection}" HorizontalAlignment="Left" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemsTemplate>
<DataTemplate>
<TextBlock Text="{Binding}">
</DataTemplate >
</ItemsControl. ItemsTemplate >
</ItemsControl>

How can I bind a dataset directly to a TreeView (with hierarchy)?

If I have a DataSet as a result of a SQL query, can I bind it directly to a TreeView and show the hierarchy of my data? I know I'd have to use several HierarchicalDataTemplates, but I don't know how to tell each one what data to display.
If I have a 4-level hierarchy, like so:
<HierarchicalDataTemplate x:Key="FirstLevelTemplate" ItemTemplate="{StaticResource SecondLevelTemplate}"/>
<HierarchicalDataTemplate x:Key="SecondLevelTemplate" ItemTemplate="{StaticResource ThirdLevelTemplate}"/>
<HierarchicalDataTemplate x:Key="ThirdLevelTemplate" ItemTemplate="{StaticResource FourthLevelTemplate}"/>
<DataTemplate x:Key="FourthLevelTemplate"/>
What property(ies) need to be set to display my data directly from a DataSet?
edit: Ideally, I'd like to do this using a single self-referencing DataTable.
I do not think you can do that.
The Treeview control, and the HierarchicalDataTemplate expect a hierarchy of objects. The DataSet is inherently flat.
You will have to somehow convert that dataset to a hierarchy of objects, each with its own "Children" collection. The ItemsSource of the treeview will be bound to the "top level collection" (the rows without a parent reference).
Each HierarchicalDataTemplate will have its ItemsSource property bound to the corresponding Children property.
There might be a solution using converters, but if it exists it would probably end up being more complicated than straight up reshaping the data before binding.
This site has some very good examples of using treeview.
BeaStollnitz
First, you would set the ItemsSource of the TreeView to the DataSet.
Next you would set the ItemTemplate of the TreeView to the FirstLevelTemplate.
ItemTemplate="{StaticResource FirstLevelTemplate}"
The first template must reference the items that will use the second level template. Add an items source to this hierarchical template like so:
<HierarchicalDataTemplate x:Key="FirstLevelTemplate" ItemsSource="{Binding ChildItems}" ItemTemplate="{StaticResource SecondLevelTemplate}"/>
Change "ChildItems" to refer to the property within your DataSet that contains the child items. Repeat this for each HierarchicalDataTemplate.
Finally, you need to add controls to your DataTemplates in order to display the data. Here's a simple example:
<DataTemplate x:Key="FourthLevelTemplate"/>
<Border BorderThickness="1" BorderBrush="Gray" CornerRadius="3">
<TextBlock Text="{Binding DataProperty}"
HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</DataTemplate>
In this case, you would replace "DataProperty" with the property name of your data field. Note that you could add other controls (like TextBox, ComboBox, etc) to display additional data.

Resources