3
votes

I'm writing a UWP app to track TV shows watched/purchased/streamed etc and am going absolutely crazy trying to get grid columns inside a DataTempate to stretch their width as it seems there is a bug in XAML which ignores the * width definition. I need the first column in the ListView (the show Title) to take up the remaining space (hence the column definition = "*") and while it will do that in the HeaderTemplate it absolutely refuses to do it inside the DataTemplate so the whole grid just ends up being all wonky and out of alignment as the Title column only uses the space it needs on each line.

My XAML is below - in the ItemTemplate DataTemplate template I am binding to an instance of an object called TVShow which is in an observable collection in my main view model. (I have not included the ViewModel or TVShow class definition here as I know this is a purely XAML issue).

The only thing that worked so far is having an extra property in my TVShow class that stores the correct width of the column (by subtracting the widths of the other three columns from the grid size (fetched in the view code behind) but this causes the whole list to reformat itself after initally displaying which looks ugly, not to mention awful programming.

So I'm looking for ideas on how to solve this - I could move the property for the correct column width in the main viewmodel but then how do I bind to that in the template given I am binding to "TVShow"? Or do I have to take the content out of the DataTemplate and put in a UserControl? I have wasted so much time on something that is so ridiculously simple - this bug seems to have been around since WPF so why haven't MS ever fixed this - very frustrating.

<HubSection Name="hsShows" Width="{Binding HubSectionWidth}" MinWidth="430" MaxWidth="640" 
            VerticalAlignment="Top" HorizontalAlignment="Stretch" Background="{StaticResource Dark}" >

    <HubSection.Header>
        <TextBlock Text="Shows" TextLineBounds="TrimToBaseline" OpticalMarginAlignment="TrimSideBearings" 
                                   FontSize="24" Foreground="{StaticResource Light}"/>
    </HubSection.Header>

    <DataTemplate x:DataType="local:MainPage">

        <ListView Name="lvwShows" 
                                  Width="{Binding HubSectionGridWidth}"
                                  Grid.Row="0" 
                                  Foreground="{StaticResource Light}"
                                  Background="{StaticResource Dark}"
                                  Margin="-14,20,0,0" 
                                  Loaded="lvwShows_Loaded"
                                  ItemsSource="{Binding AllShows}"                             
                                  HorizontalAlignment="Stretch"
                                  HorizontalContentAlignment="Stretch" 
                                  IsSwipeEnabled="True"
                                  IsItemClickEnabled="True"
                                  SelectedItem="{Binding SelectedTVShow, Mode=TwoWay}"                                
                                  SelectionMode="Single"                              
                                  ScrollViewer.VerticalScrollMode="Enabled"
                                  ScrollViewer.VerticalScrollBarVisibility="Auto">

            <ListView.ItemContainerStyle>
                <Style TargetType="ListViewItem">
                    <Setter Property="HorizontalAlignment" Value="Stretch" />
                </Style>
            </ListView.ItemContainerStyle>

            <ListView.HeaderTemplate>
                <DataTemplate>
                    <Grid Width="{Binding HubSectionGridWidth}" Height="Auto" Background="DarkGreen" Margin="15,5,5,5" HorizontalAlignment="Stretch">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="80"/>
                            <ColumnDefinition Width="100"/>
                            <ColumnDefinition Width="80"/>
                        </Grid.ColumnDefinitions>

                        <TextBlock Grid.Column="0" Text="Title" FontSize="16"  FontWeight="Bold" Foreground="{StaticResource Bright}" 
                                                   VerticalAlignment="Bottom" HorizontalAlignment="Left" 
                                                   Tag="TITLE,ASC" Tapped="ShowsGridHeading_Tapped"/>

                        <TextBlock Grid.Column="1"  Text="Seasons" FontSize="16"  FontWeight="Bold" Foreground="{StaticResource Bright}" 
                                                   VerticalAlignment="Bottom" HorizontalAlignment="Center" 
                                                   Tag="SEASONS,ASC" Tapped="ShowsGridHeading_Tapped"/>

                        <TextBlock Grid.Column="2" Text="Last Watched" FontSize="16"  FontWeight="Bold" Foreground="{StaticResource Bright}" 
                                                   VerticalAlignment="Bottom" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap" 
                                                   Tag="WATCHED,ASC" Tapped="ShowsGridHeading_Tapped"/>

                        <TextBlock Grid.Column="3" Text="Last Episode" FontSize="16"  FontWeight="Bold" Foreground="{StaticResource Bright}" 
                                                   VerticalAlignment="Bottom" HorizontalAlignment="Center" TextAlignment="Center" TextWrapping="Wrap" 
                                                   Tag="EPISODE,ASC" Tapped="ShowsGridHeading_Tapped"/>
                    </Grid>
                </DataTemplate>
            </ListView.HeaderTemplate>

            <ListView.ItemTemplate>
                <DataTemplate x:DataType="model:TVShow">
                    <Grid Height="Auto"  MinWidth="410" MaxWidth="640"  Background="Blue" HorizontalAlignment="Stretch" RightTapped="ShowsList_RightTapped">

                        <FlyoutBase.AttachedFlyout>
                            <MenuFlyout Placement="Bottom">
                                <MenuFlyoutItem x:Name="UpdateButton" Text="Update from TVMaze" Click="FlyoutUpdateButton_Click"/>
                                <MenuFlyoutItem x:Name="RefreshButton" Text="Refresh" Click="FlyoutRefreshButton_Click"/>
                                <MenuFlyoutItem x:Name="DeleteButton" Text="Delete Show" Click="FlyoutDeleteButton_Click"/>
                            </MenuFlyout>
                        </FlyoutBase.AttachedFlyout>

                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="*"/>
                            <ColumnDefinition Width="80"/>
                            <ColumnDefinition Width="100"/>
                            <ColumnDefinition Width="80"/>
                        </Grid.ColumnDefinitions>

                        <TextBlock Grid.Row="0" Grid.Column="0" Text="{x:Bind Title}"  Foreground="{StaticResource Light}"
                                                   VerticalAlignment="Center" HorizontalAlignment="Stretch" TextWrapping="Wrap" />

                        <TextBlock Grid.Row="0" Grid.Column="1" Text="{x:Bind Seasons}"  Foreground="{StaticResource Light}"
                                                   VerticalAlignment="Center" HorizontalAlignment="Center"/>

                        <TextBlock Grid.Row="0" Grid.Column="2"   Foreground="{StaticResource Light}"
                                                   Text="{x:Bind LastWatchedDate, Mode=OneWay, Converter={StaticResource DateTimeFormatConverter}, ConverterParameter='{}{0:dd/MM/yyy HH\\\\:mm}'}"                            
                                                   VerticalAlignment="Center" HorizontalAlignment="Center"/>

                        <TextBlock Grid.Row="0" Grid.Column="3" Text="{Binding LastWatchedEpisodeRef}"  Foreground="{StaticResource Light}"
                                                   VerticalAlignment="Center" HorizontalAlignment="Center"/>
                    </Grid>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </DataTemplate>
</HubSection>
3

3 Answers

6
votes

Ok, so I ended up adding this XAML into my ListViews (though I know I could have done what Grace suggested but I just find Blend horrific to use) - it was the HorizontalContentAlignment that actually did the trick!

<ListView.ItemContainerStyle>
    <Style TargetType="ListViewItem">
        <Setter Property="HorizontalAlignment" Value="Stretch" />
        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
    </Style>
</ListView.ItemContainerStyle>
1
votes

If you have Correct width in viewmodel you can Bind it like this

Width={Binding ElementName = ListViewname,Path=DataContext.width}
1
votes

This problem is caused by the default template of the ListViewItem, to make the Grid stretch inside of the items, you can open the Document Outline label => find your ListView control and right click on it, then choose Edit Additional Templates => select Edit Generated Item Container (ItemContainerStyle), and at last Edit a Copy.

enter image description here

Then you will find this template in your Page resources, please change the code:

<Setter Property="HorizontalContentAlignment" Value="Left" />

To:

<Setter Property="HorizontalContentAlignment" Value="Stretch" />

Then your problem can be solved.

I saw you've more then one ListView, if you want this style target all the ListView in this page, you can remove the x:Key attribute of this template and remove the ItemContainerStyle with the StaticResource which is generated by the action upper.

Don't be frustrating, I think you have developed WPF before, it's easy to learn UWP. Editing the template or the styles of the controls can solve many layout problem, here is some default templates and styles of different controls, you may take a look next time you have such problem.

If you have questions about how to develop an UWP app, you can refer to Develop UWP apps, and if you have some problems with the APIs, you may refer to Reference for Universal Windows apps.

If you need help or suggestion, you may ask question here, people here are glad to help.