UWP listview groups style - c#

I am creating UWP application. There is a listview, with groups.
XAML code goes like this:
<Page.Resources>
<CollectionViewSource x:Name="ContactsCVS" IsSourceGrouped="True" />
<!-- When using x:Bind, you need to set x:DataType -->
<DataTemplate x:Name="ContactListViewTemplate" x:DataType="data:Contact">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Ellipse x:Name="Ellipse"
Grid.RowSpan="2"
Width ="32"
Height="32"
Margin="6"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Fill="LightGray"/>
<TextBlock Grid.Column="1"
Text="{x:Bind Name}"
x:Phase="1"
Style="{ThemeResource BaseTextBlockStyle}"
Margin="12,6,0,0"/>
<TextBlock Grid.Column="1"
Grid.Row="1"
Text="{x:Bind Position}"
x:Phase="2"
Style="{ThemeResource BodyTextBlockStyle}"
Margin="12,0,0,6"/>
</Grid>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{x:Bind ContactsCVS.View}"
ItemTemplate="{StaticResource ContactListViewTemplate}"
SelectionMode="Single"
ShowsScrollingPlaceholders="True"
Grid.Row="1"
Grid.ColumnSpan="2" x:Name="listViewMain">
<ListView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate x:DataType="data:GroupInfoList">
<TextBlock Text="{x:Bind Key}"
/>
</DataTemplate>
</GroupStyle.HeaderTemplate>
</GroupStyle>
</ListView.GroupStyle>
</ListView>
</Grid>
And everything is ok, except that I want to make each group to have some kind of border. Like this:
How to achieve this?

As #Ken Tucker said, you can edit the GroupStyle and use GroupStyle.Panel property to add a border for each group. For example, using a GroupStyle like the following:
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate x:DataType="data:GroupInfoList">
<TextBlock Text="{x:Bind Key}"
Style="{ThemeResource TitleTextBlockStyle}" />
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<StackPanel BorderBrush="Red" BorderThickness="1" Margin="8,0,18,0" />
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
However, you may find there is no effect with using this GroupStyle in your code. This is because GroupStyle.Panel can't work with UI virtualization. If the ListView uses a virtualizing panel such as ItemsWrapGrid or ItemsStackPanel, then GroupStyle.Panel won't have effect. And for ListView its default ItemsPanel is a ItemsStackPanel. So you will also need to change ListView's ItemsPanel like:
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
Then you should be able to see the border for each group. For more info, please refer to this case. And also please note that using GroupStyle.Panel might influence the performance as the lack of UI virtualization. You may consider whether to use this according to your real scenario.

Related

ItemsControl with row and column headers WPF

I need to represent updatable list ObservableCollection<RegisterBean> listOfRegisters of objects RegisterBean as matrix with row and column headers Object contain 3 properties:
byte deviceAddress;
byte register;
byte[] data;
And only one property data should be displayed.
The expected result is like on image:
I reached this structure with usual datagrid but the problem was to update it because I used a converter with new DataTable() as a returned value. This is not correct because it flickers and rerenders all objects.
I asked for a help yesterday here. And this solution is working:
<ItemsControl ItemsSource="{Binding listOfRegisters}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="16"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Data, Converter={StaticResource ByteToStringValueConverter}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
But I didn't understand how to change the structure of usercontrol and to add headers. The result of the solution with itemscontrol:
Thanks!
UPD:
The headers should be static without any sorting and stuff like that
I start saying that probably, checking what's wrong with DataGrid would be better and that is not necessary to re-write Controls, but if you still want to use the ItemsControl ...
Supposing that there are two collections (ColHeaders & RowHeaders) in your ViewModel that contains your Headers you can add two other panels that hold headers..
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"/>
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<!-- Column Headers -->
<ItemsControl Grid.Column="1" Grid.Row="0" ItemsSource="{Binding ColHeaders}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding}" Width="30" Height="30"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<ItemsControl Grid.Row="1" Grid.Column="1" ItemsSource="{Binding listOfRegisters}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="16"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Data, Converter={StaticResource ByteToStringValueConverter}}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- RowHeaders -->
<ItemsControl Grid.Column="0" Grid.Row="1" ItemsSource="{Binding RowHeaders}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding}" Width="30" Height="30"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
I also sized the TextBlocks and the TextBoxes in order to align everything.
Just add a Grid around it, like this:
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid Grid.Row="0" Grid.Column="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Label Grid.Column="0" Content="Col 0"/>
<Label Grid.Column="1" Content="Col 1"/>
<Label Grid.Column="2" Content="Col 2"/>
</Grid>
<Grid Grid.Row="1" Grid.Column="0">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Content="Row 0"/>
<Label Grid.Row="1" Content="Row 1"/>
<Label Grid.Row="2" Content="Row 2"/>
</Grid>
<UniformGrid Rows="3" Columns="3" Grid.Column="1" Grid.Row="1">
<Button Content="00"/>
<Button Content="01"/>
<Button Content="02"/>
<Button Content="10"/>
<Button Content="11"/>
<Button Content="12"/>
<Button Content="20"/>
<Button Content="21"/>
<Button Content="22"/>
</UniformGrid>
</Grid>

Scrolling of Pivot inside Grid

I am trying to create a page that has an outer grid that splits the page in half with a pivot in on of the grid columns.
Code:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Pivot Grid.Row="1" Grid.Column="1">
<Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" FontSize="18" />
</DataTemplate>
</Pivot.HeaderTemplate>
<PivotItem x:Name="Tab1" Header="Tab 1">
<ListView x:Name="matchesList">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Data">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind Match}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</PivotItem>
<PivotItem x:Name="Tab2" Header="Tab 2">
</PivotItem>
</Pivot>
</Grid>
I would like the pivot item to scroll. I have tried placing the scrollviewer around lots of the inside elements but around the entire pivot is the only way it shows up. The ListView populates correctly but just runs off the end of the screen and is still not scroll-able. How can I get the ListView to scroll inside the pivot?
Thanks!
As I've tired, if you enable IsHorizontalScrollChainingEnabled, it should work:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Pivot Grid.Row="1" Grid.Column="1">
<Pivot.HeaderTemplate>
<DataTemplate>
<TextBlock Text="{Binding}" FontSize="18" />
</DataTemplate>
</Pivot.HeaderTemplate>
<PivotItem x:Name="Tab1" Header="Tab 1">
<ListView x:Name="matchesList" ScrollViewer.IsHorizontalScrollChainingEnabled="True">
<ListView.ItemTemplate>
<DataTemplate x:DataType="local:Data">
<Grid>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{x:Bind Match}"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</PivotItem>
<PivotItem x:Name="Tab2" Header="Tab 2">
</PivotItem>
</Pivot>
</Grid>
Generally scrolling ScrollViewer is handled on a very low level to gain performance. Though this has also some disadvantages - it brings problems when you want to use PointerEvents. To make life easier, two properties have been designed - vertical/horizontal chaining - this allows to pass vertical/horizontall scroll from child to parent - like in your example - ListView scrolls vertically and Pivot horizontally.

Extracting data templates in user controls

There are known problems for setting up caliburn binding in DataTemplates.
In this answer EisenbergEffect suggests extracting Data Templates into a user control.
How can this be achieved?
In my user control I have lots of DataTemplates and ran into those problems. Conventions are not applied and I have to use "classical" Binding.
I could only imagine to extract the whole control with the DataTemplate, this would give me lots of smaller controls, but I see no way to only extract the DataTemplate.
Here is an example XAML
<Grid>
<Grid.Resources />
<Grid.RowDefinitions>
<RowDefinition Height="10*" />
<RowDefinition Height="2*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Border HorizontalAlignment="Stretch"
BorderBrush="Transparent"
BorderThickness="0">
<ScrollViewer HorizontalContentAlignment="Stretch"
Background="Yellow"
BorderBrush="Transparent"
BorderThickness="0"
CanContentScroll="True"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto">
<!-- Conventions work here -->
<ListView x:Name="Computers"
HorizontalContentAlignment="Stretch"
Background="Red"
BorderThickness="0">
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="Transparent"
BorderBrush="Transparent"
BorderThickness="0">
<ListView HorizontalContentAlignment="Stretch"
Background="Black"
ItemsSource="{Binding HardwareComponents}"> <!-- Conventions to not work here -->
<ListView.ItemTemplate>
<DataTemplate>
<Border Background="Aquamarine"
BorderBrush="DarkGray"
BorderThickness="1">
<Grid Background="Transparent" cal:Message.Attach="[Event MouseDown] = [Action Expand($dataContext)]" >
<Grid.RowDefinitions>
<RowDefinition Height="20" />
</Grid.RowDefinitions>
<Border BorderBrush="Red" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<!-- Even more DataTemplates come here -->
</Border>
</Grid>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollViewer>
</Border>
</Grid>

ScrollViewer does not react to the Grid.Row position

My StackPanel and ScrollViewer seem to just not end at the Grid.Row position. I am making a Metro app so it is mandatory for the grid to be dynamic, as well as all the elements.
The code:
<Grid Background="#FFE4E4E4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="0.5*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="0.5*"/>
<RowDefinition Height="0.5*"/>
</Grid.RowDefinitions>
<!--News/Leaderboard Feed-->
<StackPanel Grid.Column="0" Grid.Row="0">
</StackPanel>
<!--Marketplace Feed-->
<StackPanel Grid.Column="0" Grid.Row="1">
</StackPanel>
<!--Detailed Marketplace Account-->
<StackPanel Grid.Column="1" Grid.Row="1">
</StackPanel>
<!--Marketplace View-->
<StackPanel Grid.Column="1" Grid.Row="0" VerticalAlignment="Top">
<ScrollViewer VerticalAlignment="Top">
<!--Allows scrolling-->
<GridView x:Name="MarketplaceFeed" ItemsSource="{Binding StockList}" ItemTemplate="{StaticResource MarketplaceFeedTemplate}" VerticalAlignment="Top">
<!--Displays the stock markets the user is interested in.-->
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal" />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</ScrollViewer>
</StackPanel>
</Grid>
You should put the ScrollViewer on the outside. This will auto-fit to the grid, and anything inside it will get the scrolling treatment.
<!--Marketplace View-->
<ScrollViewer VerticalAlignment="Top" Grid.Column="1" Grid.Row="0">
<StackPanel VerticalAlignment="Top">
<!-- other content -->
</StackPanel>
</ScrollViewer>

WPF DataGrid Scrollbar

I'm trying to make a WPF DataGrid show scrollbars when necessary.
You can see the basic XAML code of my user control below:
<Grid x:Name="Data" Grid.Column="0" VerticalAlignment="Stretch" Height="Auto" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Expander Header="Route Setup" Grid.Row="0" VerticalAlignment="Top" Background="White">
</Expander>
<Expander Header="Select Locations" Grid.Row="1" VerticalAlignment="Top" Background="White">
</Expander>
<DataGrid Grid.Row="2" ItemsSource="{Binding Locations, Mode=TwoWay}" Height="Auto" AutoGenerateColumns="False" ScrollViewer.CanContentScroll="True"
ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto">
</DataGrid>
This isn't working, I don't see any scroolbars when the DataGrid grows beyond the available space. I've already tried to use a scrollview around my DataGrid but that doesn't change anything.
Update
It might be important to know that the usercontrol is loaded into the LeftRegion of a shell that has the following markup:
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions >
<ColumnDefinition Width="*" MinWidth="400" MaxWidth="600"/>
<ColumnDefinition Width="9" />
<ColumnDefinition Width="*" MinWidth="300" />
</Grid.ColumnDefinitions>
<GridSplitter x:Name="MainSplitter" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Grid.Column="1"
Margin="0" Width="9" Style="{DynamicResource gridSplitterVerticalStyle}"/>
<ItemsControl Name="LeftRegion" Grid.Column="0" Background="Azure" Height="Auto" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" cal:RegionManager.RegionName="LeftRegion">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
<ItemsControl Name="RightRegion" Height="Auto" Background="DarkGreen" VerticalAlignment="Stretch" VerticalContentAlignment="Stretch" Grid.Column="2" cal:RegionManager.RegionName="RightRegion">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</Grid>
Best Regards
Jay
In your grid named "Data", remove the Height="Auto" from the third RowDefinition. At least one row must have the "*" height (which is the default) to take the remaining available space.
Solved it. I needed to remove Height="Auto" from the thrird RowDefinition.

Categories

Resources