Search code examples
c#wpfdatatemplate

formatting datatemplate using grid


Can a grid be used inside a data template to format to align the elements of the datatemplate?

I am very new to wpf and I am trying to format the presentation of a listbox by using a data template. I defined a grid within the datatemplate but it appears that the textblocks I defined was not placed in the columns I expected.

I defined a 3 column 1 row grid and planned to place each element in each respective column, but the results I got looks like this:

enter image description here

I was expecting to see the elements aligned properly in the columns I specified. What did I do incorrectly?

I have attached my xaml for illustration

    <Window x:Class="TestWPF.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:TestWPF"
                    mc:Ignorable="d"
                    Title="MainWindow"
                    Height="350"
                    Width="525">
        <StackPanel>
            <ListBox x:Name='FruitList'>
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width='10*' />
                                <ColumnDefinition Width='10*' />
                                <ColumnDefinition Width='1*' />
                            </Grid.ColumnDefinitions>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="*" />
                            </Grid.RowDefinitions>
                            <TextBlock Text='{Binding FruitName}'
                                                 Grid.Column='0' />
                            <TextBlock Text='{Binding FruitColor}'
                                                 Grid.Column='1' />
                            <CheckBox IsChecked='{Binding Selected}'
                                                Grid.Column='2' />
                        </Grid>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </StackPanel>
    </Window>

And my code behind:

namespace TestWPF
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            FruitList.ItemsSource = Fruits.getAllFruit();
        }
    }
}

With the binding data:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TestWPF.Models
{
    public class Fruit
    {
        public string FruitName { get; set; }
        public string FruitColor { get; set; }
        public bool Selected { get; set; }

    }
}


namespace TestWPF.Models
{
    public class Fruits
    {
        private static List<Fruit> _fruitList;

        static Fruits()
        {
            _fruitList = new List<Fruit>();
            _fruitList.Add(new Fruit
            {
                FruitName = "Mango",
                FruitColor = "Yellow",
                Selected = false
            });
            _fruitList.Add(new Fruit
            {
                FruitName = "Mango",
                FruitColor = "Yellow",
                Selected = false
            });
            _fruitList.Add(new Fruit
            {
                FruitName = "Water Melon",
                FruitColor = "Green",
                Selected = false
            });
            _fruitList.Add(new Fruit
            {
                FruitName = "Apple",
                FruitColor = "Red",
                Selected = false
            });
            _fruitList.Add(new Fruit
            {
                FruitName = "Banana",
                FruitColor = "Yellow",
                Selected = false
            });
            _fruitList.Add(new Fruit
            {
                FruitName = "Orange",
                FruitColor = "Orange",
                Selected = false
            });
        }
        public static List<Fruit> getAllFruit(bool bSelected = false)
        {
            var result = (bSelected ?
                                        _fruitList.Where(x => x.Selected = true).ToList<Fruit>()
                                        : _fruitList.ToList<Fruit>());
            return result;
        }
    }
}

Solution

  • IsSharedSizeScope is set to true for outer main grid and inside data template, SharedSizeGroup is applied to 3 columns. You can put any name to it. Same width will be applied to those columns.

    <Grid IsSharedSizeScope="True">
        <ListBox x:Name='FruitList' HorizontalContentAlignment="Stretch">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto" SharedSizeGroup="A" />
                            <ColumnDefinition Width="Auto"  SharedSizeGroup="B" />
                            <ColumnDefinition Width="*"  />
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="*" />
                        </Grid.RowDefinitions>
                        <TextBlock Text="{Binding FruitName}" Margin="5"
                                             Grid.Column="0" />
                        <TextBlock Text="{Binding FruitColor}" Margin="5"
                                             Grid.Column="1" />
                        <CheckBox IsChecked="{Binding Selected}" Margin="5" HorizontalAlignment="Right"
                                            Grid.Column="2" />
                    </Grid>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
    

    enter image description here