How to make vertical scrolling list view with groups - xaml

I need to create a vertical scrolling list view with grouping enabled as shown below:
This is what I currently have:
<common:VariableSizeListViewWithSelection ItemsSource="{Binding Source={StaticResource cvs}}"
ScrollViewer.VerticalScrollBarVisibility="Auto"
IsItemClickEnabled="True"
ItemTemplateSelector="{StaticResource summaryViewTemplateSelector}" >
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="0,0,0,2">
<TextBlock Grid.Column="0" Text="{Binding Title}" Margin="0,-11,10,10" Style="{StaticResource SubheaderTextBlockStyle}" TextWrapping="NoWrap" FontWeight="SemiBold" Foreground="#333333" />
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
<common:VariableSizeListViewWithSelection.GroupStyle>
<GroupStyle HidesIfEmpty="True">
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Background="LightGray" Margin="0">
<TextBlock Text='{Binding Title}' Foreground="Black" Margin="5" Style="{StaticResource HeaderTextBlockStyle}"/>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal" MaximumRowsOrColumns="4" Width="300" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</common:VariableSizeListViewWithSelection.GroupStyle>
</common:VariableSizeListViewWithSelection>
But this is not working as expected and it creates a listview with correct grouping but with just one column like this:
Can you please point me as to what am I doing wrong?

We took it offline for a bit and it seems like changing the ItemsPanel of the ListView to a StackPanel make this work. I have a feeling the default ItemsStackPanel should still support grouping, but perhaps not with a custom group layout panel. Maybe there is a way to reconfigure a GridView to scroll vertically and this could work too.

Related

Full height of content in listview with ItemsWrapGrid as panel template windows 10 app

I am trying to have the content of gridview cell to stretch the height so there is no scrolling within the cell.
Here's my code:
<Grid Grid.Row="1" Padding="50 10 50 10">
<ListView IsTapEnabled="False"
Background="White"
SizeChanged="categoryListView_SizeChanged"
x:Name="categoryListView"
Height="auto"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch"
ItemsSource="{Binding Source={StaticResource stores}, Path=CollectionGroups}"
ItemTemplate="{StaticResource CategoriesList}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<ItemsWrapGrid Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
</Grid>
and here is my data template:
<DataTemplate x:Key="CategoriesList">
<Grid x:Name="AlphabetGrid" VerticalAlignment="Top" HorizontalAlignment="Left" Margin="0 0 20 0">
<TextBlock x:Name="CategoryName" FontSize="24" Text='{Binding Group.Key}' Foreground="#412141" FontWeight="Bold" HorizontalAlignment="Left" TextAlignment="Left"/>
<Grid Margin="0 30 0 0">
<ListView ItemsSource="{Binding Group.Items}" HorizontalAlignment="Stretch" VerticalAlignment="Top">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Margin="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="4*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" x:Name="unit_number" FontSize="15" Text='{Binding unit}' Foreground="red" HorizontalAlignment="Left" TextAlignment="Left"/>
<TextBlock Grid.Column="1" x:Name="name" FontSize="15" Text='{Binding name}' Foreground="red" HorizontalAlignment="Left" TextAlignment="Left"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Grid>
</DataTemplate>
How can I achieve this? Any recommendations?
This is how it looks right now.
I can reproduce your issue: it seems that ItemsWrapGrid uses some strange logic when row heights are calculated automatically. You can set its ItemHeight property manually to avoid this problem, but this solution is far from being elegant.
Alternatively you can use the WrapPanel XAML Control from the UWP Community Toolkit as an ItemsPanelTemplate for your ListView to make the items stretch their height to fit the content
<ListView>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<controls:WrapPanel/>
<ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ListView>
however, your grid is going to have a lot of empty space then
If that's not what you want, you can eliminate most of the empty spaces by changing the orientation of the WrapPanel from horizontal to vertical
and even further by not grouping your items into separate controls by category

XAML parsing/layout rendering time very high

I've got the problem, that I create an App, that will run on Windows Phone 8.1 and Windows 10 Mobile. This App is a non-UWP Windows Store App.
The problem I have is, that I have a list of a custom control that one has another List, that is not expanded (=collapsed). That looks like this:
The red rectangles are the ContentPresenter items of the first ItemControl and the green rectangles are the ContentPresenter items of the ItemControl in the first lists items, that is not visible on startup. It will be visible after the click on the expand-button. Both ItemControls have a DataTemplate configured to present what you see in the screenshot. (XAML code below)
The main problem I have is, that if I change the Pivot to the Pivot you see at the screenshot above, there is a freeze of the app for several seconds. It depends on the device how long this freeze is. In the W10M-Emulator on my PC I don't recognize a freeze but on a Lumia 620 with WP8.1 I have a freeze of 8.5 seconds.
In the profiler of Visual Studio it looks like this (I selected the range that is the problem I am talking about):
What I am wondering about is the large orange line with "Layout". If I expand it to the "big players", there is 60-70ms for each not visible item in the profiler.
I am asking myself why this is the case, even if the items are not visible and are in the VirtualizingStackPanel. The Number of Items of the ItemSourcein this example is 3 for the first ItemControl (red boxes) and 17, 59 and 1 for the second ItemControls that are only visible of the first item is expanded.
What I am also wondering about is, that regarding the timeline, all of the Items are processed at the same time because their baseline is for all items the same. But if I scroll down the profiler timeline details, I see another Event called "Parsing" for each item. That one is not processed in parallel for each item but serial. And the parsing of the last item fits to the end of the layout-event. This parsing events look like this:
What is the reason why the parsing takes so long time? I don't think that the controls are very complex etc. and there are no code behind procedures except some string formattings.
Finally here is the XAML code:
My PivotItem on the "MainPage" of the App:
<PivotItem
Header="Echtzeit"
Margin="10,-20,10,0"
>
<Grid>
<ScrollViewer
VerticalScrollBarVisibility="Visible"
>
<ItemsControl
ItemsSource="{Binding RealtimeDepartures, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
HorizontalAlignment="Stretch"
Margin="0"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:RealtimeStation
StationName="{Binding StationName, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
Departures="{Binding DepartureList, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
FontSize="{Binding DataContext.ClientFontSize, ElementName=MainPg, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</PivotItem>
The RealtimeStation Control XAML:
<UserControl
...
>
<UserControl.Resources>
<dec:BoolToVisibilityConverter x:Key="BoolToVisibilityConv"/>
</UserControl.Resources>
<Grid>
<AppBarButton
HorizontalAlignment="Left"
VerticalAlignment="Top"
Grid.Column="0"
Name="btnExpand"
Icon="{Binding ExpandButtonIcon, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
Click="btnExpand_Click"
IsEnabled="{Binding IsExpandButtonEnabled, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
IsCompact="True"
Margin="0,-8,-2,-4"
/>
<StackPanel
Orientation="Vertical"
Margin="48,12,0,0"
>
<TextBlock
Text="{Binding StationName, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
VerticalAlignment="Center"
FontSize="24"
/>
<TextBlock
Text="Derzeit stehen keine Abfahrten an"
FontStyle="Italic"
Visibility="{Binding ShowNoDepartures, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
FontSize="{Binding FontSize, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
/>
<TextBlock
Text="Zugausfälle vorhanden!"
Foreground="Red"
FontWeight="Bold"
Visibility="{Binding ShowTrainCanceled, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
FontSize="{Binding FontSize, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
/>
<ItemsControl
ItemsSource="{Binding DepartureList, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
ScrollViewer.VerticalScrollBarVisibility="Visible"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
Margin="-48,0,0,0"
Visibility="{Binding IsExpanded, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, Converter={StaticResource BoolToVisibilityConv}}"
>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentPresenter>
<controls:RealtimeDeparture
DepartureDetails="{Binding}"
FontSize="{Binding FontSize, ElementName=main, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
/>
</ContentPresenter>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</Grid>
</UserControl>
And finally the RealtimeDeparture Control:
<UserControl
...
>
<Grid>
<control:DisruptionIcon
Height="24"
Width="50"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Icon="{Binding TrainIcon, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
Margin="3"
/>
<StackPanel
Orientation="Vertical"
Margin="56,9,0,0"
>
<StackPanel
Orientation="Horizontal"
Margin="3,0"
VerticalAlignment="Center"
>
<TextBlock
Text="{Binding DelayTimeText, ElementName=main, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Foreground="{Binding DelayColor, ElementName=main, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
/>
<TextBlock
Text="{Binding DepartureDetailsText, ElementName=main, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"
Margin="3,0"
/>
</StackPanel>
<TextBlock
Text="{Binding InformationText, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, ElementName=main}"
Visibility="{Binding IsInformationVisible, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, ElementName=main}"
Margin="3"
FontStyle="Italic"
TextWrapping="Wrap"
/>
<TextBlock
Text="Zug fällt aus!"
Foreground="Red"
FontWeight="Bold"
Visibility="{Binding IsCanceledVisible, UpdateSourceTrigger=PropertyChanged, Mode=OneWay, ElementName=main}"
Margin="3"
/>
</StackPanel>
</Grid>
</UserControl>
Does anybody has an idea how to speed up this parsing? What is the reason why it is so slow? Do I have a design issue that is disabling the virtualization-functionality of the VirtualizedStackPanel? I already tried a lot but didn't find the reason why it is so slow.
I don't think virtualization is turned on.
Try setting the CanContentScroll property to true on your ScrollViewer:
<ScrollViewer
CanContentScroll="true"
VerticalScrollBarVisibility="Visible"
>
The other option can be using e.g. ListBox which supports virtualization on its own (as far as I know it is enough to set the ItemsPanelTemplate to VirtualizingStackPanel)

enable user left click on the items of gridview but disable right click and select an item in xaml

<GridView
Grid.Row="1"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
ItemsSource="{Binding ServiceOrderList}"
ItemTemplate="{StaticResource ServiceOrderListItemTemplate}"
SelectedItem="{Binding SelectedServiceOrder, Mode=TwoWay}"
IsSwipeEnabled="false">
<winRtBehaviors:Interaction.Behaviors>
<behaviors:EventToBoundCommandBehavior
Command="{Binding ServiceOrderItemClickCommand}"
Event="Tapped" />
</winRtBehaviors:Interaction.Behaviors>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Vertical" MaximumRowsOrColumns="3" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
I want use to be able to do a left click on the items of gridview but dosn't want to allow them to right click and select an item, please help.
If you don't want the items to be selectable at all, set SelectionMode="None" and IsItemClickEnabled="True" along with setting an ItemClick event.
If you want them to be selectable, but only left click, you can set IsRightClickEnabled="False".
Another way is put RightTapped event in your GridView.ItemTemplate which is implement : e.Handled = true
<GridView>
<GridView.ItemTemplate>
<DataTemplate>
<Grid Margin="30,10"
Width="350" Tapped="Grid_Tapped_1" RightTapped="Grid_RightTapped">
<StackPanel Orientation="Vertical">
<StackPanel Orientation="Horizontal">
<Image Height="40" Source="{Binding Path=Image}" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="0,-3,11,0"/>
<TextBlock FontSize="24" FontWeight="SemiBold" FontFamily="Segoe WP" Foreground="#232323" Text="{Binding Path=RoomTypeString}" VerticalAlignment="Center"/>
</StackPanel>
<TextBlock FontSize="24" Text="{Binding Path=RoomCountString}"
Foreground="#232323" FontFamily="Segoe WP"
TextTrimming="CharacterEllipsis"/>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>

how to make listbox is resizable inside its parent?

In a user control, I put a listbox which is bound to a dynamic datasource. This usercontrol will be in a popup window. I want to this list box can fill the rest of space of the window. Here is the Xaml I tried:
<ComboBox x:Name="cmbx1" Grid.Column="0" Grid.Row ="0" Margin="5"
Width="150" VerticalAlignment="Center" HorizontalAlignment="Left" SelectionChanged="filters_SelectionChanged">
......
</ComboBox>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Grid.Column="1" Grid.Row="0">
<Button Content="Test" Margin="5" Click="Button_Add" />
</StackPanel>
<DataGrid x:Name="ListGrid" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2"
......
</DataGrid>
<ComboBox x:Name="cmb2" Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="5">
......
</ComboBox>
<ListBox x:Name="lstSharing" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Margin="0,0,10,0"
Width="{Binding Width, ElementName=ListGrid}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<tkit:WrapPanel Orientation="Horizontal" MaxWidth="650" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="3" Width="Auto">
<CheckBox IsChecked="{Binding IsChecked, Mode=TwoWay}" />
<TextBlock Text="{Binding ItemName}" Width="120" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
What I want it height and width of list box can be setup dynamically based on windows size, the items bound to list box. But it is not working properly. Initially, the listbox has no scrollbar, I need to resize window manually so that scrollbar on display. I can not dynamically to change with, so I put MaxWidth =600. Otherwise, it always display all item in one row.
How to resolve this problem?
This is untested, but I would try something like this:
<ListBox x:Name="lstSharing"
Grid.Row="3"
Grid.Column="0"
Grid.ColumnSpan="2"
Margin="0,0,10,0"
HorizontalAlignment="Stretch"
VerticalAlignment="Stretch">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<tkit:WrapPanel Orientation="Horizontal"
MaxWidth="{Binding ElementName=lstSharing, Path=ActualWidth}" />
</ItemsPanelTemplate>
It's a little difficult to know whether this will work without seeing the parent containers, but it should point you in the right direction.

semantic zoom control throwing exception when groups are empty

have a semantic zoom control in an application where I've got three groups (today, tomorrow and later), but the groups don't necessarily always have at least one item. The semantic zoom control works perfect when all three groups are non-empty, but not whenever any of the items are empty. I've tried clearing out my DataTemplate to ensure it's nothing to do with the bindings, and I couldn't find an event to hook on to so that I could potentially step through what was going on when the zoom-out event is triggered.
Has anyone got this working, or have any ideas/suggestions/tips/workarounds?
some code:
XAML - collectionviewsource:
<!-- Collection of grouped items displayed by this page -->
<CollectionViewSource
x:Name="groupedItemsViewSource"
Source="{Binding Groups}"
IsSourceGrouped="True"
ItemsPath="Items"
d:Source="{Binding ItemGroups, Source={d:DesignInstance Type=data:AuctionDataSource, IsDesignTimeCreatable=True}}"/>
XAML - semantic zoom control:
<SemanticZoom Visibility="Collapsed" Grid.Row="1" Name="MainSemanticZoom">
<SemanticZoom.ZoomedInView>
<GridView
x:Name="itemGridView"
AutomationProperties.AutomationId="ItemGridView"
AutomationProperties.Name="Grouped Items"
Margin="116,0,40,46"
ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}"
SelectionMode="Multiple"
SelectionChanged="itemGridView_SelectionChanged_1">
<GridView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left" Width="250" Height="200" RightTapped="Grid_RightTapped_1" Tag="{Binding}">
<Border Background="{StaticResource ListViewItemPlaceholderRectBrush}">
<Image Source="{Binding Image}" Stretch="UniformToFill"/>
</Border>
<StackPanel Grid.Column="1" VerticalAlignment="Bottom" Background="{StaticResource ListViewItemOverlayBackgroundBrush}">
<!--bindings: Title , CurrentBid, CloseDate -->
<TextBlock Text="{Binding Title}" Foreground="{StaticResource ListViewItemOverlayTextBrush}" Height="20" Style="{StaticResource TitleTextStyle}" Margin="15,0,15,0"/>
<TextBlock Text="{Binding CurrentBid, Converter={StaticResource FormatStringConverter}, ConverterParameter='\{0:C}'}" Foreground="{StaticResource ListViewItemOverlayTextBrush}" Style="{StaticResource TitleTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,0"/>
<TextBlock Text="{Binding CloseDate, Converter={StaticResource FriendlyTimeConverter}}" Foreground="{StaticResource ListViewItemOverlayTextBrush}" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="15,0,15,10"/>
<Border Visibility="{Binding IsLeading, Converter={StaticResource BooleanToVisibilityConverter}}" Name="leadingBlock" Background="CadetBlue">
<TextBlock Text="leading" Style="{StaticResource BodyTextStyle}" Margin="15,0,15,10"></TextBlock>
</Border>
<Border Visibility="{Binding IsOutbid,Converter={StaticResource BooleanToVisibilityConverter}}" Name="outbidBlock" Background="Orange">
<TextBlock Text="outbid" Style="{StaticResource BodyTextStyle}" Margin="15,0,15,10"></TextBlock>
</Border>
<Border Visibility="{Binding NoBids,Converter={StaticResource BooleanToVisibilityConverter}}" Name="noBidsBlock" Background="Gray">
<TextBlock Text="you have not placed a bid" Style="{StaticResource BodyTextStyle}" Margin="15,0,15,10"></TextBlock>
</Border>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<Grid Margin="5,0,30,10">
<!--<Button
AutomationProperties.Name="Group Title"
Content="{Binding Title}"
Click="Header_Click"
Style="{StaticResource TextButtonStyle}"/>-->
<TextBlock Text="{Binding Title}" Style="{StaticResource SubheaderTextStyle}"></TextBlock>
</Grid>
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<VariableSizedWrapGrid Orientation="Vertical" Margin="0,0,80,0"/>
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
</GridView>
</SemanticZoom.ZoomedInView>
<SemanticZoom.ZoomedOutView>
<GridView
x:Name="itemZoomOutGridView"
AutomationProperties.AutomationId="ItemZoomOutGridView"
AutomationProperties.Name="Grouped Items"
SelectionMode="None">
<GridView.ItemTemplate>
<DataTemplate>
<Grid HorizontalAlignment="Left">
<Border Background="{StaticResource ListViewItemPlaceholderRectBrush}">
<Image Height="750" Source="{Binding Group.Image}" Stretch="UniformToFill"/>
</Border>
<StackPanel Height="140" Width="400" Background="Orange" VerticalAlignment="Center">
<TextBlock Margin="15" Text="{Binding Group.Title}" Foreground="White" Style="{StaticResource HeaderTextStyle}"></TextBlock>
<TextBlock Margin="15" Grid.Row="1" Text="{Binding Group.Items.Count}" Foreground="White" Style="{StaticResource HeaderTextStyle}"/>
</StackPanel>
</Grid>
</DataTemplate>
</GridView.ItemTemplate>
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Margin="230,0,0,0" Width="2000" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</SemanticZoom.ZoomedOutView>
</SemanticZoom>
I "solved" this by handling the ViewChangeStarted and the ViewChangeCompleted events of the SemanticView control. In the ViewChangeStarted event I added a new item, so that group won't be empty, and in the ViewChangedCompleted event I removed it. It's not a fix, just a workaround, but it does the job.
I don't think this is SemanticZoom issue. We reported very similar issue with GridView with grouped source. If any of the groups were empty we got exception. In fact CollectionViewSource is the likely culprit in this.
Our solution was not to use GridView with grouping. You can configure ItemsControl to look just like grouped GridView. The only downside to this is that you can't select items from different groups at the same time, but for us it was not an issue, since we didn't need selection.