Treeview with wrappanel - flexible grouping - wpf

I'n trying to resolve problem with treeview.
I would like to get items (UserControls) ordered inside wrappanel, in treeview node.
-Group
|---------------------------------------------|
|Item Item Item Item Item Item Item Item Item |
|---------------------------------------------|
+Group
+Group
If window width (and along treeview width) suppress and items wont fit to one line, those should be ordered to next line.
-Group
|-------------------------|
|Item Item Item Item Item |
|Item Item Item Item |
|-------------------------|
+Group
+Group
I have done above example which won't put items on next row. This is working without Treeview, but inside treeview-node something is missing..
<DataTemplate x:Key="GroupTemplateFrontPage">
<Border BorderBrush="AliceBlue" BorderThickness="1" CornerRadius="10"
Background="{StaticResource TreeViewItemBackground}" >
<Expander HeaderTemplate="{DynamicResource HeaderTemplate}"
Header="{Binding}" IsTabStop="False" HorizontalAlignment="Left"
IsEnabled="True" ExpandDirection="Down" IsExpanded="True">
<Grid Margin="5,5,5,5">
<Grid.ColumnDefinitions>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox Margin="10,39,0,0" VerticalAlignment="Top" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding Modems}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel
HorizontalAlignment="Stretch"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Disabled"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Controls:UserControlItem Margin="4" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Expander>
</Border>
</DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="Treeview" />
<TreeView Name="_treeView" ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Margin="0,0,0,0"
ItemsSource="{Binding}"
ItemTemplate="{StaticResource GroupTemplateFrontPage}" />
</StackPanel>

Setting the ItemsPanel for TreeViewItems should do:
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
</TreeView.ItemContainerStyle>
Also turn off horizontal scrolling to allow for wrapping:
<TreeView ScrollViewer.HorizontalScrollBarVisibility="Disabled" ...>

Related

WPF ItemControl Virtualization, Items Visibility Issue

I have an ItemControl that is virtualized and work perfectly. But when I change visibility of items from Visible to Collapsed and vice versa, it takes too long to rerender itemControl items.
<ItemsControl ItemsSource="{Binding Persons}" Grid.Row="1" VirtualizingStackPanel.IsVirtualizing="True" VirtualizingPanel.ScrollUnit="Pixel" ScrollViewer.CanContentScroll="True" Margin="0,1,0,0">
<ItemsControl.Template>
<ControlTemplate TargetType="{x:Type ItemsControl}">
<ScrollViewer CanContentScroll="True">
<ItemsPresenter/>
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical" IsItemsHost="True"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Height="40" Style="{StaticResource RowGridStyle}" Visibility="{Binding VisibilityProperty}">
<!--Some UI Content-->
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
this XAML is work fine when i change ItemsSource (Persons) properties. Even if I change 1000 persons name, the UI changes fast.
BUT when the VisibilityProperty of 100 persons changes, the UI rerender too long.
Any helps ?

Listview virtualization fails when applying a Data Template

I can get a large amount of items to display within a Listview.
However, when I apply a DataTemplate, the listsview does not display any items.
This works:
<ListView x:Name="ContactList" ItemsSource="{Binding SelectedCategory.Contacts}"
Height="425"
Width="425"
Margin="58,175,0,0" Canvas.ZIndex="99"
Background="Transparent" Foreground="#FF333747"
VerticalAlignment="Top" HorizontalAlignment="Left">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Border>
<ScrollViewer>
<ItemsPresenter/>
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="Hello Wworld" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListView>
This doesn't:
<ListView x:Name="ContactList" ItemsSource="{Binding SelectedCategory.Contacts}"
Height="425"
Width="425"
Margin="58,175,0,0" Canvas.ZIndex="99"
Background="Transparent" Foreground="#FF333747"
VerticalAlignment="Top" HorizontalAlignment="Left">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate TargetType="ItemsControl">
<Border>
<ScrollViewer>
<ItemsPresenter/>
</ScrollViewer>
</Border>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding DisplayName}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListView>
It appears that displaying listview items using a data template fails once a binding is applied.
How can I resolve this?
My list was displaying several items that had empty strings.
As a result of this list being sorted in ascending order, the items that displayed empty text showed up at the beginning of the list while the other items did exist but were not within the scrollviewer's viewport.
As a result I did this:
foreach (var contact in phoneContacts)
{
if (string.IsNullOrWhiteSpace(contact.DisplayName))
{
continue;
}
.
.
.
}

ScrollViewer content is scrolling over other parts of window

I have the following as part of my XAML:
<DockPanel>
<ToolBar Name="toolbar1" DockPanel.Dock="Top" Height="41" Background="#FFA5D95A">
//other controls
</ToolBar>
<ScrollViewer>
<ListBox Name="listBox1" ItemsSource="{Binding ElementName=This, Path=Items}"
ItemTemplateSelector="{StaticResource entryItemTemplateSelector}">
<ListBox.Template>
<ControlTemplate>
<WrapPanel IsItemsHost="True" />
</ControlTemplate>
</ListBox.Template>
</ListBox>
</ScrollViewer>
</DockPanel>
I want the scrool bar to move the items in the ListBox just to the top of the WrapPanel, and then to stop showing them when they get to the top; in stead, these items scroll into the ToolBar at the top.
What am I doing wrong?
Note: Haing been asked, here are the DataTemplates I currently have; EntryItemHost is a type derived from WindowsFormsHost.
<DataTemplate x:Key="folderTemplate">
<my:EntryItemHost Item="{Binding}"
Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:MainWindow, AncestorLevel=1}, Path=Background}"
DoubleClick="FolderDoubleClick" />
</DataTemplate>
<DataTemplate x:Key="imageTemplate">
<my:EntryItemHost Item="{Binding}"
Background="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:MainWindow, AncestorLevel=1}, Path=Background}" />
</DataTemplate>
Instead of setting ListBox Template set the ItemsPanel and remove the ScrollViewer
sample
<DockPanel>
<ToolBar Name="toolbar1"
DockPanel.Dock="Top"
Height="41"
Background="#FFA5D95A">
//other controls
</ToolBar>
<ListBox Name="listBox1" ItemsSource="{Binding ElementName=This, Path=Items}"
ItemTemplateSelector="{StaticResource entryItemTemplateSelector}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding ActualWidth, RelativeSource={RelativeSource FindAncestor, AncestorType=ContentPresenter}}" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</DockPanel>
notice that I have replaced the template with ItemsPanel and restricted the width to the listbox
I made this based on the assumptions, let me know is this not what you are looking for

User Controls Wrapped inside a panel MVVM

I am new to WPF/Xaml and searched for this issue I am facing but found it tough. Requesting some help on this.
I need to display usercontrols (DATABOUND) (horizontally) inside a panel/listview so that they wrap when the width of listview/panel is met, with a vertical scroll bar autoshown (as in figure).
so far I have this code.
<ListView Grid.Row="3"
ItemsSource="{Binding Controls}"
VerticalAlignment="Bottom" Background="{x:Null}" BorderBrush="{x:Null}"
>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,10"></StackPanel>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="VerticalContentAlignment" Value="Bottom"/>
<Setter Property="Focusable" Value="False" />
</Style>
</ListView.ItemContainerStyle>
<!--<ListView.ItemTemplate>
<DataTemplate>
<ContentControl Content="{Binding}" VerticalContentAlignment="Bottom"/>
</DataTemplate>
</ListView.ItemTemplate>-->
</ListView>
I have even tried the below code. Yes, it wraps but no scrollbar appears!
<ItemsControl Grid.Row="3"
Width="100" Height="200"
ItemsSource="{Binding Controls}"
VerticalAlignment="Bottom" Background="{x:Null}" BorderBrush="{x:Null}"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" Margin="0,0,0,10"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
Note: I am okay with any control that makes this happens. Not necessarily be a listview.
To wrap items you need to set ItemsPanel to WrapPanel, like in second example, but you may need to disable horizontal scrolling on ListView:
<ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled" .../>
also, if you want to use ItemsControl then ScrollViewer is not part of default Template, like for ListView, so you'll need to wrap in in ScrollViewer
<ScrollViewer Grid.Row="3">
<ItemsControl ...>
<!-- .... -->
</ItemsControl>
</ScrollViewer>
and don't forget to move Grid.Row="3" from ItemsControl definition to ScrollViewer
You were close :-)
Put your listview with a view panel that is a wrapanel inside your scrollviewer.
<ScrollViewer>
<ItemsSource="{Binding Controls}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</ScrollViewer>
You are using Wrap panel so you need to specify the width it supposed to take... since wrappanel is inside a items host control wrap panel itself cannot calculate the width.It will try to take all the width with respective to Orientation (in your case its horizontal)
Here is the sample code with list box as items host... in this code i have binded the wrappanel width to the actual width of the list box so that it will never take more width than the list box and also i disabled the horizontal scrolling which you don't need for horizontal orientation and vertical wrapping
Note: Make sure to change item template before using following code and it will work with all items hosts like ListView, ItemsControl...
<ListBox Width="500" Height="500" Name="listbox" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" Width="{Binding ActualWidth,ElementName=listbox}"></WrapPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Height="100" Width="100">
<TextBlock Text="{Binding}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
For ItemsControl
<ItemsControl Grid.Row="3"
Width="100" Height="200"
ItemsSource="{Binding Controls}"
VerticalAlignment="Bottom" Background="{x:Null}" BorderBrush="{x:Null}"
Name="listbox"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" Orientation="Horizontal" Width="{Binding ActualWidth,ElementName=listbox}"></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer x:Name="ScrollViewer" Padding="{TemplateBinding Padding}">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Height="30" Width="30">
<TextBlock Text="{Binding}" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Silverlight ItemsControl vertical scrollbar, using a wrappanel as ControlTemplate

I have a collection of elements, each one with a name and a subcollection of image blobs.
I want to display an Accordion, with each item representing each of the MainElements. inside each element, I display the images in the subcollecion of said MainElement.
The Accordion gets resized by the user, so I use a wrappanel for presenting the images. When the accordion is wide enough, the images reorder themselves fitting as many as posible in each row.
the problem comes when the wrappanel only displays one image per row (because there's no space enough for more), the image list continues, but I can't see all the images, because they don't fit inside the control's height.
I need a vertical scrollbar to be displayed inside the AccordionItem so I can scroll down the image list.
So, here's my code:
<layoutToolkit:Accordion Width="Auto" Height="Auto" ItemsSource="{Binding MainElementCollection}">
<layoutToolkit:Accordion.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding MainElementName}" />
</DataTemplate>
</layoutToolkit:Accordion.ItemTemplate>
<layoutToolkit:Accordion.ContentTemplate>
<DataTemplate>
<ItemsControl ItemsSource="{Binding SubElementCollection}" ScrollViewer.VerticalScrollBarVisibility="Auto" >
<ItemsControl.Template>
<ControlTemplate>
<controlsToolkit:WrapPanel />
</ControlTemplate>
</ItemsControl.Template>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Image Margin="2" Width="150" Source="{Binding PreviewImage, Converter={StaticResource ImageConverter}}" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</DataTemplate>
</layoutToolkit:Accordion.ContentTemplate>
</layoutToolkit:Accordion>
http://www.silverlightshow.net/tips/How-to-add-scrollbars-to-ItemsControl.aspx suggests that I should surround my wrappanel with a scrollviewer, like this
<ItemsControl.Template>
<ControlTemplate>
<scrollviewer>
<controlsToolkit:WrapPanel />
</scrollviewer>
</ControlTemplate>
</ItemsControl.Template>
But then my wrappanel gets really small and I can only see a small vertical scrollbar
Any ideas?
Thanks a lot.
Edit: I figured thatthe wrappanel loses its width when used in the controltemplate
It should be used as follows:
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controlsToolkit:WrapPanel ScrollViewer.VerticalScrollBarVisibility="Visible" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
Anyway, I tried adding the ScrollViewer.VerticalScrollBarVisibility="Visible" line but I'm stuck again.
Edited again:
Now my wrappanel looks like this:
<ItemsControl ItemsSource="{Binding StageVideos}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controlsToolkit:WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Margin="2" Width="150" Cursor="Hand" MouseLeftButtonDown="videoPreview_MouseLeftButtonDown" Tag="{Binding}" Source="{Binding PreviewImage, Converter={StaticResource ImageConverter}}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer VerticalScrollBarVisibility="Visible">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
I'm using a wrappanel as the items panel, and I'm using the ControlTemplate to surround the presenter with a scrollviewer. Still, no luck :/
It's working perfectly. i had two different Accordions on the same page, and I was checking my code changes in the one whose code I wasn't touching.
Sometimes you need to pause, go for a walk and then look at the whole screen.
The right code is the last one:
<ItemsControl ItemsSource="{Binding StageVideos}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controlsToolkit:WrapPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Margin="2" Width="150" Cursor="Hand" MouseLeftButtonDown="videoPreview_MouseLeftButtonDown" Tag="{Binding}" Source="{Binding PreviewImage, Converter={StaticResource ImageConverter}}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer VerticalScrollBarVisibility="Visible">
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>

Resources