I have performance problem with my listview/gridview.
I traced it down to the view not being virtualized. I removed all business critical code and was left with the following XAML.
<UserControl x:Class="Weingartner.Controls.PointListEditorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300"
x:Name="Root">
<Grid>
<ListView ItemsSource="{Binding ElementName=Root, Path=Points, Mode=OneWay}">
<ListView.View>
<GridView >
<GridViewColumn>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Label>Foo</Label>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Grid>
</UserControl >
When I look in the visual debugger I see this
The ListViewItem instances continue for the full list of the data, ie about 800 points.
When I open up any of the ListViewItem objects I see that they are fully populated as below
As far as I understand the docs say that virtualization is on by default for ListBox and ListView. Is this correct?
Any suggestions?
Edit: This is a screenshot of the full visual tree:
We are using MahApps.Metro and after setting the default ListView style to
VirtualisedMetroListView virtualising works:
<Style BasedOn="{StaticResource VirtualisedMetroListView}" TargetType="ListView" />
Related
I had an ObservableCollection<MyDataType>object named myCollection that I was presenting in a GUI using a <DataTemplate> in my .XAMLfile (See code below).
But now the type of myCollection has changed to a Dictionary<UInt64,MyDataType>.
How would I present it now? Here I found an implementation of an ObservableDictionary<>. But I don't know how I would bind this to my GUI?
Thank you for any assistance!
<Page x:Class="Project.ThisPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-ThisPage.ProjectSpace"
mc:Ignorable="d"
d:DesignHeight="480" d:DesignWidth="640"
Title="ThisPage"
Name="thisPage">
<Page.Resources>
<DataTemplate x:Key="MyDataTemplate" DataType="{x:Type local:MyDataType}">
<Label Content="{Binding Name}"/>
<Label Content="{Binding Id}"/>
</DataTemplate>
</Page.Resources>
<Grid>
<ScrollViewer>
<StackPanel>
<ItemsControl ItemsSource="{Binding ElementName=thisPage,Path=myCollection}" ItemTemplate="{StaticResource MyDataTemplate}" />
</StackPanel>
</ScrollViewer>
</Grid></Page>
myCollection.Values will give you MyDataType collection and myCollection.Keys will give you UINT64 collection. So bind to MyDataType collection just update binding like:
ItemsControl ItemsSource="{Binding ElementName=thisPage,Path=myCollection.Values}" ItemTemplate="{StaticResource MyDataTemplate}" />
How to create a hovered toolbar?
Clicking to expand the ToolBar will not shrink the Canvas.
Expander works for expanding, but the canvas will get shrinked.
<UserControl x:Class="smartgrid.studio.View.GraphicEditorView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:model="clr-namespace:smartgrid.studio.Model"
xmlns:studio="clr-namespace:smartgrid.studio"
xmlns:metro="clr-namespace:MahApps.Metro.Controls;assembly=MahApps.Metro"
mc:Ignorable="d"
d:DesignHeight="1000" d:DesignWidth="1000">
<DockPanel>
<Expander DockPanel.Dock="left" Header ="Toolbar" FontSize="18" ExpandDirection="Up">
<TreeView Name="GraphicEditorEntityTree" Background="Transparent" BorderBrush="Transparent" ItemsSource="{Binding GraphicEditorEntities}"/>
</Expander>
<Canvas/>
</DockPanel>
</UserControl>
You can overlay things by putting them in a Grid without rows or columns, the sizing of your toolbar is an independent matter (you can still use an expander for that).
http://msdn.microsoft.com/en-us/library/system.windows.controls.panel.zindex.aspx
Panel.ZIndex might be the solution.
<Grid x:Name="LayoutRoot">
<Grid x:Name="Toolbar" Panel.ZIndex="1000" Visibility="Collapsed">
</Grid>
<canvas />
</Grid>
I'm having trouble with a freshly created blank page in Xaml/win8. Here is my code:
<common:LayoutAwarePage
x:Name="pageRoot"
x:Class="MyApp.Contents"
DataContext="{Binding DefaultViewModel, RelativeSource={RelativeSource Self}}"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:MyApp"
xmlns:common="using:MyApp.Common"
xmlns:data="using:MyApp.Data"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.Resources>
<!-- Collection of items displayed by this page -->
<CollectionViewSource
x:Name="itemsViewSource"
Source="{Binding Items}"
d:Source="{Binding TestSource.Items, Source={d:DesignInstance Type=data:MyDataSource, IsDesignTimeCreatable=True}}"/>
</Page.Resources>
<!-- Snip Grid and Back Button -->
<ListView
x:Name="itemListView"
AutomationProperties.AutomationId="ItemsListView"
AutomationProperties.Name="Items"
TabIndex="1"
Grid.Row="1"
Margin="-10,-10,0,0"
Padding="120,0,0,60"
ItemsSource="{Binding Source={StaticResource itemsViewSource}}"
IsSwipeEnabled="False"
ItemTemplate="{StaticResource ItemTemplate}"/>
And here is the C# which backs it (TestSource constructor):
for (int i = 0; i < 20; ++i)
TestSource.Items.Add(new ExampleData(TestSource));
In the designer, this works properly. I see a list of 20 ExampleData exactly as you expect.
However, when I run the app, nothing is displayed on the page. None of the "ExampleData" items show up (even though I'm sure the "TestSource.Items" observable collection got properly filled.
I've mostly copy/pasted this binding example from the SplitView demo. Does anyone see what's wrong? =[
Your source for the CollectionViewSource is pointed at Items, not TestSource.Items. Your design source is correct but when you are running it would be wrong. Should be:
<CollectionViewSource
x:Name="itemsViewSource"
Source="{Binding TestSource.Items}"
d:Source="{Binding TestSource.Items, Source={d:DesignInstance Type=data:MyDataSource, IsDesignTimeCreatable=True}}"/>
I have a user-control containing this XAML
<UserControl x:Class="QA.JobListControl" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:QA" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources>
<CollectionViewSource x:Name="itemsSource" IsSourceGrouped="True" />
</UserControl.Resources>
<ListView x:Name="JobListView" Margin="-10,-10,0,0" Padding="120,0,0,60" IsSwipeEnabled="False" ItemsSource="{Binding Source=itemsSource}" SelectionChanged="JobListView_SelectionChanged" SelectionMode="Single">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Border HorizontalAlignment="Stretch">
<TextBlock Text='{Binding Status}' Margin="10" />
</Border>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Margin="10">
<TextBlock Text='{Binding TaskName}' />
<TextBlock Text='{Binding DueDate}' />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</UserControl>
And to set the content I am using this C#-code
itemsSource.Source = Tasks.OrderBy(Tsk => Tsk.DueDate).GroupBy(Tsk => Tsk.Status);
It is showing some of the elements (but they are shown as empty elements), and not all are shown
What could be wrong?
If I am using this C#-code it is working (but it is not grouped)
JobListView.ItemsSource = Tasks.OrderBy(Tsk => Tsk.DueDate);
UPDATE
After adding the StaticResource like below, it now shows multiple groups without items
ItemsSource="{Binding Source={StaticResource itemsSource}}"
So I think you are misunderstanding the basics behind the GroupBy method. GroupBy, as opposed to most other Linq extensions, will not return a simple list of objects, instead it will return a list of IGrouping. IGrouping interface exposes a Key property which will hold the value of the grouping discriminator you passed in the GroupBy lambda.
Therefore, to get the list to display the group name, you have to bind the group header template to Key instead of Status.
<TextBlock Text='{Binding Key}' Margin="10" />
Also if reference your CollectionViewSource as a resource, you need to define a resource key to reference it later in your XAML as a StaticResource.
<CollectionViewSource x:Name="itemsSource" x:Key="groupedTasks" IsSourceGrouped="True" />
And in the list view.
<ListView x:Name="JobListView" ItemsSource="{Binding Source={StaticResource groupedTasks}}">
This way I got your example to work as expected.
As an additional read I dearly recommend you to read this article by Sergei Barskiy which demonstrates how to use grouping in XAML lists and also provides a GroupedData class that in my opinion is much better than the default IGrouping object to expose your data and consume it in the UI.
I am writing an application in which I utilize a tab control which will start with one tab open but allows the user to open multiple other tabs.
Each tab that is openned should have a treeview inside which I fill using databinding when the user loads a file.
I am new to WPF but I feel as if there is a way in which I can create a template containing each of the elements the TabItems should contain. How can I do this using templates? Right now my WPF for the tab items is the following
<TabItem Header="Survey 1">
<TreeView Height="461" Name="treeView1" VerticalAlignment="Top"
Width="625" Margin="0,0,6,0" ItemTemplateSelector="{StaticResource TreeviewDataSelector}" />
</TabItem>
I think you want something like this:
<Window x:Class="TestWpfApplication.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<DataTemplate x:Key="TabItemTemplate">
<TreeView Height="461" Name="treeView1" VerticalAlignment="Top"
Width="625" Margin="0,0,6,0" ItemTemplateSelector="{StaticResource TreeviewDataSelector}" />
</DataTemplate>
</Window.Resources>
<Grid>
<TabControl ItemsSource="{Binding ListThatPowersTheTabs}"
ItemTemplate="{StaticResource TabItemTemplate}">
</TabControl>
</Grid>
You basically create re-usable templates as static resources which you refer to by their key name.
Usually in this sort of situation I bind my TabControl.ItemsSource to a ObservableCollect<ViewModelBase> OpenTabs, so my ViewModel is in charge of adding/removing new tabs as needed.
Then if you want something in every Tab, then overwrite the TabControl.ItemTemplate and use the following line to specify where to display the currently selected TabItem
<ContentControl Content="{Binding }" />
If you don't need to setup something in every single tab, you don't need to overwrite the TabControl.ItemTemplate - it will default to displaying the currently selected ViewModelBase in the Tab.
And I use DataTemplates to specify which View to use
<DataTemplate TargetType="{x:Type local:TabAViewModel}">
<local:TabAView />
</DataTemplate>
<DataTemplate TargetType="{x:Type local:TabBViewModel}">
<local:TabBView />
</DataTemplate>
<DataTemplate TargetType="{x:Type local:TabCViewModel}">
<local:TabCView />
</DataTemplate>