0
votes

I am trying to display something like a score board, with team name in top 25% of a square and score taking up lower 75% (with font ratios as appropriate). I also want these controls to grow/shrink as the window gets resized.

To do this I have created a grid and split it into * and 3* rows. I have added one TextBlock to the top row and another TextBlock spanning bottom 4 rows. Then I have wrapped each TextBox in a ViewBox

This causes an application to go into a "break mode".

This shows the issue:

<Window x:Class="WpfRandoms.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfRandoms"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="3*"/>
        </Grid.RowDefinitions>

        <ListView ItemsSource="{Binding Teams}" HorizontalAlignment="Center" Grid.Row="0" BorderBrush="{x:Null}" Background="{x:Null}">
            <ListView.ItemsPanel>
                <ItemsPanelTemplate>
                    <StackPanel Orientation="Horizontal" />
                </ItemsPanelTemplate>
            </ListView.ItemsPanel>
            <ListView.ItemContainerStyle>
                <Style TargetType="{x:Type ListViewItem}">
                    <Setter Property="Background" Value="Transparent" />
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type ListViewItem}">
                                <ContentPresenter />
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListView.ItemContainerStyle>
            <ListView.ItemTemplate>
                <DataTemplate>
                    <Border Margin="10" Padding="10" CornerRadius="5" Width="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*" />
                                <RowDefinition Height="3*" />
                            </Grid.RowDefinitions>
                            <Viewbox Grid.Row="0">
                                <TextBlock Text="{Binding Name}" TextAlignment="Center" />
                            </Viewbox>
                            <Viewbox Grid.Row="1">
                                <TextBlock Text="{Binding Score}" FontSize="40" TextAlignment="Center" />
                            </Viewbox>
                        </Grid>
                    </Border>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
    </Grid>
</Window>

With code-behind:

using System.Collections.Generic;
using System.Windows;

namespace WpfRandoms
{
    public partial class MainWindow : Window
    {
        public class Team
        {
            public string Name { get; set; }
            public int Score { get; set; }
        }

        public IList<Team> Teams { get; private set; }

        public MainWindow()
        {
            InitializeComponent();

            Teams = new List<Team>();
            Teams.Add(new Team() { Name = "Team A", Score = 78 });
            Teams.Add(new Team() { Name = "Team B", Score = 1 });
            Teams.Add(new Team() { Name = "Team C", Score = 101 });

            DataContext = this;
        }
    }
}

This seems to be caused by the StackPanel used as ItemsPanelTemplate of a ListView (without this StackPanel everything works fine but the layout is not as desired). However, I am not aware of another way of making ListView horizontal, so I am stuck with the StackPanel.

After some experimenting and reading about how ViewBox works, and how StackPanels behave I arrived at some solution (possibly not the best one).
I am wrapping my ListView in a Border, and then binding the height of a Border within the ListView's DataTemplate to the height of that outside Border.
Because of that there is a small limitation - mainly top/bottom margins cause the elements of the ListView to be trimmed. To avoid this trimming I have added padding to the Border within the DataTemplate, and then added a smaller Border within that has a background etc.
I had to also hide the vertical scrollbar of the ListView.
Here is what I have:

<Window x:Class="WpfRandoms.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="3*"/>
        </Grid.RowDefinitions>

        <Border x:Name="MyBorder" Margin="10" Grid.Row="0">
            <ListView ItemsSource="{Binding Teams}" HorizontalAlignment="Center" VerticalAlignment="Stretch" BorderBrush="{x:Null}" Background="{x:Null}" ScrollViewer.VerticalScrollBarVisibility="Hidden">
                <ListView.ItemsPanel>
                    <ItemsPanelTemplate>
                        <StackPanel Orientation="Horizontal"/>
                    </ItemsPanelTemplate>
                </ListView.ItemsPanel>
                <ListView.ItemContainerStyle>
                    <Style TargetType="{x:Type ListViewItem}">
                        <Setter Property="Background" Value="Transparent" />
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type ListViewItem}">
                                    <ContentPresenter />
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </ListView.ItemContainerStyle>
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <Border Margin="10, 0" Padding="10" Height="{Binding ActualHeight, ElementName=MyBorder}" Width="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}">
                            <Border Background="AliceBlue" CornerRadius="5">
                                <Grid>
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="*" />
                                        <RowDefinition Height="3*" />
                                    </Grid.RowDefinitions>
                                    <Viewbox Grid.Row="0">
                                        <TextBlock Text="{Binding Name}" TextAlignment="Center"/>
                                    </Viewbox>
                                    <Viewbox Grid.Row="1">
                                        <TextBlock Text="{Binding Score}" FontSize="40" TextAlignment="Center"/>
                                    </Viewbox>
                                </Grid>
                            </Border>
                        </Border>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </Border>
    </Grid>
</Window>

If there is a better solution, I would greatly appreciate it :)

2

2 Answers

1
votes

I'm not sure if I understand your problem exactly. If you are looking to keep the ratios between the name and score the same, you can use the "*" for the name (25%) and "3*" for the score (75%). You can also put each TextBlock in a Viewbox rather than the entire thing. To keep it simple, I replaced the converter and bindings with hard coded strings.

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Border Margin="10" Padding="10" CornerRadius="5" Background="Coral">
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*" />
                <RowDefinition Height="3*" />
            </Grid.RowDefinitions>
            <Viewbox Grid.Row="0">
                <TextBlock Text="Home" TextAlignment="Center" />
            </Viewbox>
            <Viewbox Grid.Row="1" >
                <TextBlock Grid.Row="1" Text="25" TextAlignment="Center" />
            </Viewbox>
        </Grid>
    </Border>
</Grid>

0
votes

I think you may have a problem with the converter you are referencing on the boarder control.

I tested your XAML without the bindings and the view box works as expected.

 <Border Margin="10" Padding="10" CornerRadius="5" Width="{Binding Path=ActualHeight, RelativeSource={RelativeSource Self}}">
        <Viewbox>
            <Grid>
                <Grid.RowDefinitions>
                    <RowDefinition Height="Auto" />
                    <RowDefinition Height="*" />
                </Grid.RowDefinitions>
                <TextBlock Text="Team Name" TextAlignment="Center" Grid.Row="0" />
                <TextBlock Text="100" FontSize="100" TextAlignment="Center" Grid.Row="1" Grid.RowSpan="3"/>
            </Grid>
        </Viewbox>
    </Border>

Hopefully this helps!