I had a Dictionary of values that I wanted to display in an XAML UI as part of a UWP app. My initial foray was to use a ListView with a binding to the dictionary  ListView.ItemTemplate/DataTemplate. The dictionary was then bound to the ListView’s ItemsSource. The problem with the ListView is that there is a lot of padding between items vertically and within items.I wanted to compact the rows of data vertically though as if I had manually placed each dictionary item (key and values) in a grid of rows of TextBlocks in a row (one row for each item). This article discusses my trials and tribulations with this issue and includes my final solution.

 

Whilst I could have explicitly created a grid with one row for each dictionary item and a TextBlock in each row for the item key and one for each of the item values, this would have been a pain for two reasons:

  • What if you had a large number of dictionary items
  • What if the number of items was variable (my main reason).

 

image

A ListView example with padding between items

 

A Typical Bound ListView

The XAML code for a typical ListView with Bound data is :

<ListView x:Name="ListCharacteristics" ItemsSource="{Binding CharacteristicOverviewAndDetails}" 
        SelectionChanged="ListChracteristics_SelectionChanged"
        HorizontalAlignment="Left" VerticalAlignment="Top"  MaxHeight="300"
        ScrollViewer.VerticalScrollBarVisibility="Visible"
        ScrollViewer.VerticalScrollMode="Enabled"
        >
    <ListView.ItemTemplate>
        <DataTemplate>
            …………
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>


The ListView gets its items from the CharacteristicOverviewAndDetails construct which is an ObservableCollection of a class with public properties AssignedNumber, Mandatory,InDevice, and  Type_s. (This construct isn’t a dictionary). The ItemTemplate lays out how each bound property for each instance of the class in the collection o\is presented. The template in this case is:

<ListView.ItemTemplate>
    <DataTemplate>
        <Grid>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="400" />
                <ColumnDefinition  Width="150"/>
                <ColumnDefinition Width="120"/>
                <ColumnDefinition Width="120"/>
                <ColumnDefinition Width="200" />
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <TextBlock Grid.Row="0" Grid.Column="0" Text="{Binding Path=Name }" TextAlignment="Left"  />
            <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=AssignedNumber_s}" TextAlignment="Center"  />
            <TextBlock Grid.Row="0" Grid.Column="2" Text="{Binding Path=Mandatory }" TextAlignment="Center"  />
            <TextBlock Grid.Row="0" Grid.Column="3" Text="{Binding Path=InDevice }" TextAlignment="Center"  />
            <TextBlock Grid.Row="0" Grid.Column="4" Text="{Binding Path=Type_s}" TextAlignment="Left"  />
        </Grid>
    </DataTemplate>
</ListView.ItemTemplate>

Explicitly Binding to an object’s properties.

When there is just one instance of an object to display you can explicitly lay it out  in a grid as. In the following example. An instance of a class callled DeviceInfo, called Device is set out:

<Grid Background="Beige" Width="810" HorizontalAlignment="Left" >
    <Grid.ColumnDefinitions >
                    <ColumnDefinition Width="200" />
                    <ColumnDefinition Width="5" />
                    <ColumnDefinition  Width="*"/>
                </Grid.ColumnDefinitions>
                <Grid.RowDefinitions>
                    <RowDefinition/>
                    <RowDefinition/>
                    <RowDefinition/>
                    ….
        <RowDefinition/>
    </Grid.RowDefinitions>
    <TextBlock Grid.Row="0" Grid.Column="0" TextAlignment="Right"  Text="Name:" 
               FontStyle="Italic"  FontWeight="Bold" Foreground="Blue"/>
    <TextBlock Grid.Row="1" Grid.Column="0" TextAlignment="Right" Text="BTAddressAsString:"
               FontStyle="Italic"  FontWeight="Bold" Foreground="Blue"/>
    <TextBlock Grid.Row="2" Grid.Column="0" TextAlignment="Right" Text="Manufacturer:"
               FontStyle="Italic"  FontWeight="Bold" Foreground="Blue"/>
               ….
    <TextBlock Grid.Row="0" Grid.Column="2" TextAlignment="Left" Text="{Binding Path=Device.Name}" />
    <TextBlock Grid.Row="1" Grid.Column="2" TextAlignment="Left" Text="{Binding Path=Device.BTAddressAsString}" />
    <TextBlock Grid.Row="2" Grid.Column="2" TextAlignment="Left" Text="{Binding Path=Device.Manufacturer}" />
    ….
</Grid>

Hint: In this class, BTAddress is formatted in the desired format as a string as the readonly (get) property BTAddressAsString.

 

image

The UI for the above XAML code.

 

Nb. Binding to Dictionary Items

Binding to items in a Dictionary implemented by binding to the dictionary item key and dictionary item value/s.

<ListView.ItemTemplate>
    <DataTemplate>
        <Grid Background="Beige" >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="200" />
                <ColumnDefinition Width="5" />
                <ColumnDefinition  Width="250"/>
                <ColumnDefinition  Width="*"/>
            </Grid.ColumnDefinitions>
            <Grid.RowDefinitions>
                <RowDefinition Height="20" />
            </Grid.RowDefinitions>
            <TextBlock Height="20"  Grid.Row="0" Grid.Column="0" TextAlignment="Right"  Text="{Binding Path=Key}" 
                      FontStyle="Italic"  FontWeight="Bold" Foreground="DarkGreen"/>
            <TextBlock Height="20"  Grid.Row="0" Grid.Column="2" TextAlignment="Left" Text="{Binding Path=Value.Item1}" />
            <TextBlock Height="20"  Grid.Row="0" Grid.Column="3" TextAlignment="Left" Text="{Binding Path=Value.Item2}" />
        </Grid>
    </DataTemplate>
</ListView.ItemTemplate>

In this case the dictionary value is a three item tuple. Item3 is a byte array. Item1 is the array cast to string. Item2 is a string formatted representation of the array bytes, each as a hex value:

public static Dictionary<DeviceProperties.SensorTagProperties, Tuple<string, string, byte>> DeviceProperties { get; set; }

SensorTagProperties is an enum:

public enum SensorTagProperties
{
    SysId, DeviceName, ModelName, SerialNumber, FirmwareDate,
    HardwareRevision, SoftwareRevision, ManufacturerId, BTSigCertification, PNPId,
    BatteryService, BatteryLevel, NOTFOUND
};

:

image

The desired presentation for the DeviceProperties

 

Remove spacing between ListView Items

Typically there is a gap between item rows. This can be removed by adding  as in the following code. Place directly before the ListView.ItemTemplate:

<ListView.ItemContainerStyle>
    <Style TargetType="ListViewItem">
        <Setter Property="Padding" Value="0" />
        <Setter Property="Margin" Value="0" />
        <Setter Property="BorderThickness" Value="1" />
        <Setter Property="BorderBrush" Value ="Black" />
        <Setter Property="VerticalContentAlignment" Value="Top" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListViewItem">
                    <ListViewItemPresenter ContentMargin="0" Padding="0" />
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ListView.ItemContainerStyle>
This puts a black board around each item. To remove it set the BorderThickness to 0.

Whilst this does compact the list vertically by removing the padding between items, there is still padding within each item which I found hard to remove.

ListView items with vertical spacing between items

 

image

ListView Items with padding between items removed

 

What is desired is to remove the internal padding for each item:

image

ListView item without any internal padding

 

I found that I couldn’t reduce the number of lines per item to less than two without some negative vertical margins, which requires a dummy value at the top. I tried setting row height, TextBlock height etc to no avail. A solution is now presented in the Addendum that zeroes the spacing between items in a ListView.

 

Part 1: XAML Layout for a Dictionary-Part1 (This)

Part 2: XAML Layout for a Dictionary-Part2

Part 3: XAML Layout for a Dictionary-Addendum