Search code examples
c#wpfdata-bindingdatagrid

How to bind list of object to DataGrid in WPF


This is my code behind:

public partial class MainWindow : INotifyPropertyChanged
{
    private List<Word> _words;

    public List<Word> Words
    {
        get => _words;
        set
        {
            _words = value;
            OnPropertyChanged("Words");
        }
    }

    public MainWindow()
    {
        InitializeComponent();

        MeaningGroup group1 = new MeaningGroup()
        {
            Synonyms = new List<string> {"synonym1", "synonym2", "synonym3"},
            Acronyms = new List<string> {"acronym1", "acronym2"}
        };

        MeaningGroup group2 = new MeaningGroup()
        {
            Synonyms = new List<string> { "synonym1"},
            Acronyms = new List<string> { "acronym1", "acronym2", "acronym3" }
        };

        MeaningGroup group3 = new MeaningGroup()
        {
            Synonyms = new List<string> { "synonym1", "synonym2" },
            Acronyms = new List<string> { }
        };

        MeaningGroup group4 = new MeaningGroup()
        {
            Synonyms = new List<string> { "synonym1" },
            Acronyms = new List<string> { "acronym1", "acronym2", "acronym3","acronym4" }
        };

        Word word1 = new Word() {Name = "word1",MeaningGroups = new List<MeaningGroup>() {group1, group2}};
        Word word2 = new Word() { Name = "word2", MeaningGroups = new List<MeaningGroup>() { group3, group4 } };
        Word word3 = new Word() { Name = "word3", MeaningGroups = new List<MeaningGroup>() { group1, group2,group4 } };
        Word word4 = new Word() { Name = "word4", MeaningGroups = new List<MeaningGroup>() { group3 } };

        Words = new List<Word> {word1, word2, word3, word4};

    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

public class Word
{
    public String Name { get; set; }
    public List<MeaningGroup> MeaningGroups { get; set; }

}

public class MeaningGroup
{
    public List<string> Synonyms { get; set; }
    public List<string> Acronyms { get; set; }
}

And this is MainWindow.xaml code:

<Window x:Class="WpfApp4.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:WpfApp4"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Grid>
    <DataGrid ItemsSource="{Binding Words}" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
            <DataGridTextColumn Header="Synonym and acronyms">
               <!-- How binding? -->
            </DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

I want to bind data objects like this: enter image description here


Solution

  • the answer below solves this problem, but I will suggest another way. As said above, first you need to add DataContext = this in your code-behide. Then just change the xaml markup as follows:

         <Grid>
            <DataGrid ItemsSource="{Binding Words}" AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
                    <DataGridTemplateColumn Header="Synonym and acronyms">
                        <DataGridTemplateColumn.CellTemplate>
                            <DataTemplate>
                                <StackPanel>
                                    <ItemsControl ItemsSource="{Binding MeaningGroups}">
                                        <ItemsControl.ItemTemplate>
                                            <DataTemplate>
                                                <StackPanel Orientation="Horizontal">
                                                    <ItemsControl ItemsSource="{Binding Synonyms}">
                                                        <ItemsControl.ItemsPanel>
                                                            <ItemsPanelTemplate>
                                                                <WrapPanel/>
                                                            </ItemsPanelTemplate>
                                                        </ItemsControl.ItemsPanel>
                                                        <ItemsControl.ItemTemplate>
                                                            <DataTemplate>
                                                                <Border BorderThickness="1" BorderBrush="Black" CornerRadius="5" Margin="5 5 0 0">
                                                                <TextBlock Margin="3" Text="{Binding}"/>
                                                                </Border>
                                                            </DataTemplate>
                                                        </ItemsControl.ItemTemplate>
                                                    </ItemsControl>
                                                    <ItemsControl ItemsSource="{Binding Acronyms}">
                                                        <ItemsControl.ItemsPanel>
                                                            <ItemsPanelTemplate>
                                                                <WrapPanel/>
                                                            </ItemsPanelTemplate>
                                                        </ItemsControl.ItemsPanel>
                                                        <ItemsControl.ItemTemplate>
                                                            <DataTemplate>
                                                                <Border BorderThickness="1" BorderBrush="Black" CornerRadius="5" Background="Red" Margin="5 5 0 0">
                                                                <TextBlock Margin="3" Text="{Binding}"/>
                                                                </Border>
                                                            </DataTemplate>
                                                        </ItemsControl.ItemTemplate>
                                                    </ItemsControl>
                                                </StackPanel>
                                            </DataTemplate>
                                        </ItemsControl.ItemTemplate>
                                    </ItemsControl>
                                </StackPanel>
                            </DataTemplate>
                        </DataGridTemplateColumn.CellTemplate>
                    </DataGridTemplateColumn>
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    

    As a result, we will get enter image description here