I have something like
<ScrollView>
<StackPanel Orientation="Vertical">
<TextBox>
<TextBox>
*** // Tons of TextBoxes
<TextBox>
<RadJumpList> // Just a ListBox from Telerik
</ScrollView>
For now, the whole page is scrollable (due to ScrollViewer) and RadJumpList is also scrollable itself (by definition). How to disable RadJumpList from scrolling?
PS: probably, too many "scroll"s per a question, but i guess its pretty intuitive :)
EDIT: from my experience, this is bad idea. If list has 100+ items, it can delay page loading for a several seconds list would be loaded whole at once. Better idea is to put all TextBoxes to the ListBox via dataTemplateSelector.
If you don't set the height of your RadJumpList and disable scrolling like ScrollViewer.VerticalScrollBarVisibility="Disabled".It will be ok.
Actually, even better way is to push all stuff into the list via ItemTemplateSelector.
Otherwise, if there would be 100+ items, page would load for a several seconds.
Related
I have a requirement which is to display a user information at top of the page and a ListView of images will follow it, and I've wrote following code (it's a pseudocode but I think it's enough to explain what I've done):
<ScrollViewer>
<StackPanel>
<Grid>
<!-- User Information Part -->
</Grid>
<ListView>
<!-- Images Part, This is a custom virtualized ListView, it's ItemsPanel is a custom VirtualizingWrapPanel -->
</ListView>
</StackPanel>
</ScrollViewer>
But in this scenario, the VirtualizingWrapPanel (by which has been tested on another individual ListView without an explicit ScrollViewer declaration and it works correctly) and the virtualization of ListView won't work because the desired height of ScrollViewer is positive infinity and all the items in the ListView will be expanded and rendered, I wonder whether there is a way that can make the ListView in ScrollViewer being virtualizable? Thanks
You can't virtualize a list that has all elements being rendered (because of the StackPanel),
A workaround that will work for you: you need a single ListView. With the first row customized to display the User Information Part, and all other rows displaying images.
I have created a list with ScrollViewer and stackpanel. I am adding user control to this stackpanel from codebehind.
I want to virtualize data that I can improve the performance of my application.
How can i achieve this?
I cann't use Listbox because I am adding user control as DataItems and each user control have a different width and height.. Please suggest how to implement that
Code:
XAML
<ScrollViewer>
<StackPanel x:Name="stckPnlComponentsLst" Visibility="{Binding IsBusy, Converter={StaticResource BooleanToVisibilityInvertedConverter}}" Orientation="Vertical">
</StackPanel>
</ScrollViewer>
C#
for (int count = 0; count < countItems; count++)
{
stckPnlComponentsLst.Children.Add(new ChannelNewsLstControl(ViewModel.ComponentData[count], false, false));
}
I don't see any case in which using a StackPanel inside a ScrollViewer is a good idea.
You should not do that.
There are 2 controls to do what you want, ListBox and ListView.
If you really want to stick with a stackpanel inside a ScrollViewer, just replace your StackPanel, by a VirtualizingStackPanel. But again, you should NOT be doing that.
Use a ListBox instead. Check the sample here. For example, define ListBox in a xaml
<ListBox x:Name="MyList">
and then in codebehind
var MyListData = new List<ChannelNewsLstControl>();
MyListData.Add(new ChannelNewsLstControl {name = "MyFirstChannelName});
MyList.ItemsSource=MyListData;
If you have really lots of items, i'd recommend to use Telerik's DataBoundListBox as it is much faster than a normal ListBox (at least, for wp7) and supports virtualization and async loading. Sample would be pretty the same, as component is inherited ListBox and adding own features mentioned before.
EDIT: final answer:
Try to put a grid inside of your ItemTemplate and set its RowDefinition.Height = "Auto". See some details here
I have a treeview at the left side of the screen, and when I click on any of the TreeViewItem, I want the right side of the screen to change accordingly.
For example, clicking on 'Project' would display on the right half of the screen, a label for project name along with the project name in a text box, and a similar label-textbox pair for some other fields. Clicking on a sub-option of 'Project' such as 'Task 1' should change the right half of the screen such that instead of labels and textboxes for project name and details, it should now be for task name/details. Atm, I only care about label-textbox pairs but in the future I'll need some more sophisticated options, maybe buttons and tables.
What I thought of was to have a grid premade for each option, when I clicked on 'Project' there would be a grid which displays all the info for a Project. And when I then clicked on 'Task 1', the Project grid should be hidden and the Task grid should be displayed with the fields filled out.
Is this possible? What should I be using to create templates that I can then choose from?
Firoz already mentioned the important bit. A rough guess is that you're not using MVVM pattern, so to minimize the adaption effort, you could add a Content Control to your window and set the content of this control whenever a selection is made. You can put any User Control in there.
Using MVVM would mean you bind that Content Control to a property on your ViewModel (of type UIElement or UserControl) and set an instance whenever a bound selected values changes. Speaking of selected Value, I think the default TreeView is not really Binding-friendly, so you might end up with behaviours that do the binding for you.
What you are asking to do is quite easy and possible, but I don't think you are thinking quite big enough.
As your project grows and the number of different things that you want to show expands, then you are going to need to show and hide more and more controls. This is quite quickly going to get unmanageable. Instead think about some other controls deal with this, in some ways you are doing something very like a tabbed dialog, just with a hierarchical set of tabs.
A tabbed dialog has a panel and a set of tabs, when you click on each tab, the content of the panel changes. In fact you can create UserControls one for each specialised set of UI that you want to display, e.g. you could have a ProjectControl that displays all of your project textboxes, labels, buttons etc.
In addition WPF has this neat feature called DataTemplates, these define how a type of data should look when it is displayed. So if you where to have a
public class MyProject
{
public string Name {get;set;}
}
Then you could define
<DataTemplate DataType="{x:Type MyProject}>
<TextBox Text="{Binding Name}"/>
</DataTemplate>
And WPF will automatically convert the data into to its visual form if you set it as the content of the tab panel.
However this type of displaying content in a panel is not the only WPF control that does this. There is also something called a NavigationFrame, which also can be used wrapped into a Window as a NavigationWindow. This control provides you ways to navigate to the next Page to display. Pages can be just like the UserControls in a tabbed dialog, but can also be URIs, enabling you to link in content from the web if you wish. In addition you can call NavigateTo from other controls enabling you build much more usable interfaces.
I worked through the process of building a full windows control panel style interface in
http://alski.net/post/2012/01/11/WPF-Wizards.aspx
and http://alski.net/post/2012/01/13/WPF-Wizards-part-2-Glass.aspx
I've added later VS2012 style glows in
http://alski.net/post/2013/09/14/WPF-Re-creating-VS2012Office-2013-window-glow.aspx
And then released the entire source code as open source at
http://winchrome.codeplex.com/
This comes with support for embedding Navigation panels with
<WinChrome:SearchableNavigationWindow
x:Class="WinChrome.Win7Demo.MainWindow"
...
xmlns:WinChrome="clr-namespace:WinChrome;assembly=WinChrome"
Style="{StaticResource Win7NavigationWindow}">
<WinChrome:SearchableNavigationWindow.Navigation>
<view:Navigation x:Name="navigationTree"/>
</WinChrome:SearchableNavigationWindow.Navigation>
(Full source code)
Where the navigation window is embedded as, but can also be a TreeView.
<UserControl x:Class="WinChrome.View.Navigation" ...>
<ScrollViewer HorizontalScrollBarVisibility="Disabled" Padding="12,0"
VerticalScrollBarVisibility="Auto" >
<StackPanel>
<Button
Margin="0,12,0,0" Style="{StaticResource LinkNavigatorButtonStyle}"
Content="Home"
Command="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Win7Demo:MainWindow}, AncestorLevel=1},
Path=GoHomeCommand}" />
</StackPanel>
</ScrollViewer>
(Full source code)
I have Listview with templated items (which looked just like Windows Explorer). My problem is when I openning folder which contains a whole lot of files that ListView loads those files not smoothly.(see video: http://screencast.com/t/bY7ucELj9I).
Does someone has any idea how to solve it?
You may need to virtualize your ListView's Items. Example
<ListView Name="ListViewWithVirtualization" Height="100" Margin="5"
VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Recycling" />
If you set VirtualizingStackPanel.VirtualizationMode = “Recycling” then each container will get reuse instead of destroy. You will get better performance by specifying VirtualizationMode to Recycling than basic default virtualization. See http://msdn.microsoft.com/en-us/library/system.windows.controls.virtualizingstackpanel.aspx
We are struggling with the slowness of the datagrid in wpf. Regardless of which collection we are using - List, BindingList, ObservableCollection, custom ObservableCollection, it's still very slow when responding to collection update (Clear, Add) and render on the screen.
The fastest solution we found is not to update the collection, but update the exsting objects in the collection, that DataGrid is bound to. In this case the grid is responding very fast, like old winforms grid.
We are creating 65535 rows in the grid, that will be enough for all our grids. When it comes to update the grid, we update the required number of top rows, and set visibility = hidden for the rest. As I said it works exteremely fast. But There are 2 issues that we cannot solve:
scroll bar, since we don't collapse the rows (it's slow) - it's always is set for 65535 row. Is there any way to limit the scroll, or grid size to the actual visible rows count?
Also, I noticed, that adding new rows into collection, if they don't need to be rendered immediately (they will be out of the visible area) is also very fast, so we can limit the minimum set to 50 rows (max visible rows), and then add/remove new rows as required. But this does not solve the problem with the scrolling.
Any other solutions are welcome.
Foreseeing the advise to enable virtualization - yes, we are using virtualization (for rows which are enabled by default, and for columns).
Update:
We are trying to display 20 columns x 50 rows of data. If we modify the source collection with Clear() and then Add(), the rendering time is about 1 second, which is not acceptable at all for us, as the UI is frozen for a second. I tried to resize the datagrid to 0 Height, and then set size back incrementally in the background thread, it unfreezes the UI, but overlook is ugly, and I haven't managed how to set datagrid back to fill the parent control. It seems after Height is set in code, there is no way back.
As in initial post, the alternate solution we found it not to modify the collection. Just limit the grid to 65535 rows, don't add or remove new items. It works really fast, but now we are facing problems in synchronizing scrolling, and sorting.
I found the datagrid is very frustrating control in WPF. The performance is below any reasonable limits.
What we are trying to achieve is responsiveness. It should not block UI more than several milliseconds, when loading the data.
XAML: nothing extraordinary
<DataGrid x:Name="TheGrid"
DockPanel.Dock="Top"
ItemsSource="{Binding Collection}"
EnableColumnVirtualization="True"
EnableRowVirtualization="True"
AutoGenerateColumns="False"
ColumnWidth="70"
RowHeight="20"
>
<DataGrid.Columns>
<DataGridTemplateColumn Header="Header 1" >
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<TextBox Text="{Binding Field1, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding Field1}" /></DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn >
..... and so on for 20 columns
Also, the datagrid is not inside a StackPanel (this makes it terrible slow).
Finally we have found how to limit the scrolling to any number of rows not hacking too much.
We created our own list for binding, which implements ICollection, which is used in ScrollView to get count of rows. We changed ICollection.Count to return count of visible rows, which we set before calling Measure, then we set it back to actual count. It works well, and it resolved all our problems with scrolling.
So, we have a grid, that is bound to list which has static number of rows, and we set visibility=Visible to n first rows that we want to show, the rest has visibility Hidden (not Collapesed, because Collapsing is very slow), and we limit the scroll to visible rows. The objects that are in list, can be updated from different threads, and we don't need to call Dispatcher, because WPF does it itself.
I have found to pages that might be useful to you.
The first is about caching the values in the datagrid:
http://msdn.microsoft.com/en-us/library/system.windows.uielement.cachemode(v=vs.100).aspx
The second it about implementing virtual mode for the datagrid:
http://msdn.microsoft.com/en-us/library/15a31akc.aspx
I hope it help you
Update:
Are you using a scroll view? Because if you are it will load all rows instead of the visible only. Try see the answer to this question: How to lazy-evaluate a wpf:DataGrid, retrieving data only as needed
I know it might not be the right solution because it still will take the same amount of time. But making it multithreading will solve the freezing problem. Then you could just let it fill data in the grid in the background and add them on the run one by one or add them all when finished.