Search code examples
c#wpfdata-bindingwpfdatagrid

Why does my DataGrid display no rows when there are items in its bound data source?


When the main window - containing only my DataGrid shows, the DataGrid shows zero rows.

This is what my grid looks like:

<DataGrid                 
        AutoGenerateColumns="True"
        CanUserAddRows="False"
        CanUserReorderColumns="True"
        CanUserResizeColumns="True"
        DataContext="ClientListViewModel"
        ItemsSource="{Binding Source=RowItems}">
    <DataGrid.Columns>
        <DataGridTextColumn Header="Given Name" Binding="{Binding GivenName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
        <DataGridTextColumn Header="Family Name" Binding="{Binding FamilyName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
        <DataGridTextColumn Header="Gender" Binding="{Binding Gender, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
        <DataGridTextColumn Header="Date of Birth" Binding="{Binding DateOfBirth, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
    </DataGrid.Columns>
</DataGrid>

In the Source={Binding Source=RowItems} the source is a property, RowItems on my main view model, ClientListViewModel.

The viewmodel has a Read method called in the ctor of ClientListView, my main view. When I debug this problem, I can see that the RowItems items source is correctly populated.

My initialization of the main view, the UserControl containing the DataGrid in question, looks like this:

public MainWindow()
{
    InitializeComponent();
    InitializeListView();
}

private void InitializeListView()
{
    var model = new ClientListViewModel();
    model.Read();
    var view = new ClientListView();
    view.DataContext = model;
    Content = view;
}

When I put a breakpoint straight after model.Read();, its model.RowItems property shows 12 items, yet the DataGrid shows no rows.

Why is my DataGrid rendering zero rows?


Solution

  • All the part are there, but they are not being arranged properly. To take advantage of DataBinding you need to follow a specific pattern. In this case you should follow these steps.

    public MainWindow() {
        InitializeComponent();
        this.Clients = InitializeListView();
        this.DataContext = this;        
    }
    
    public ClientListViewModel Clients { get; set; }
    
    private ClientListViewModel InitializeListView() {
        var model = new ClientListViewModel();
        model.Read();    
        return model;
    }
    

    And MainWindow, which you indicated only contains the DataGrid should bind its ItemSource accordingly to the properties of the DataContext of the view, which in this case is the MainWindow itself and the DataGrid will inherit as its DataContext

    <DataGrid                 
            AutoGenerateColumns="False"
            CanUserAddRows="False"
            CanUserReorderColumns="True"
            CanUserResizeColumns="True"
            ItemsSource="{Binding Clients.RowItems}">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Given Name" Binding="{Binding GivenName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
            <DataGridTextColumn Header="Family Name" Binding="{Binding FamilyName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
            <DataGridTextColumn Header="Gender" Binding="{Binding Gender, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
            <DataGridTextColumn Header="Date of Birth" Binding="{Binding DateOfBirth, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></DataGridTextColumn>
        </DataGrid.Columns>
    </DataGrid>