1

I am trying to replicate the solution from Create a custom DataGrid's ItemsSource but my rows are not populating.

The columns appears with the correct headers, but no data in the grid.

Can anyone please tell me what I am doing wrong?

using System;
using System.Windows;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;

namespace WPFBindingDataGridTest2
{
    public partial class MainWindow : Window
    {
        public ObservableCollection<MyObject> myList { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            this.DataContext = this;

            testClass = new ObservableCollection<TestClass>();
            testClass.Add(new TestClass(NameValue: "John"));
            testClass.Add(new TestClass(NameValue: "Frank"));
            testClass.Add(new TestClass(NameValue: "Sarah"));
            testClass.Add(new TestClass(NameValue: "David"));
        }
    }

    class TestClass : INotifyPropertyChanged
    {
        private string name;

        public TestClass(string NameValue)
        {
            this.Name = NameValue;
        }

        public String Name
        {
            get { return name; }
            set { this.name = value; NotifyPropertyChanged(); }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

And the XAML...

<Grid>
    <DataGrid x:Name="dataGrid" ItemsSource="{Binding testClass}" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

The error I am getting is

System.Windows.Data Error: 40 :  
BindingExpression path error:  
'testClass' property not found on 'object'''MainWindow' 
(Name='')'.BindingExpression:  
Path=testClass;  
DataItem='MainWindow' (Name='');  
target element is 'DataGrid' (Name='dataGrid');  
target property is 'ItemsSource' (type 'IEnumerable')

I feel like I am so close to this, but am just missing one thing.
Possible the data context is wrong?

ASh
  • 34,632
  • 9
  • 60
  • 82
  • 1
    Property names are case sensitive. Try to change MyId to MyID in the binding. There should be a binding error in the Output window. – Yevgeniy May 21 '17 at 00:06
  • What Yevgeniy said. But additionally, another important thing is that the binding to your collection (myList) is not being informed that the value of this property has been changed (i.e., you assigned a ObservableCollection object to this property). Hence you don't see any effect. –  May 21 '17 at 00:07
  • 2
    I suggest you create a ViewModel class, in which you declare and initialize the ObservableCollection property. Use the ViewModel class as DataContext. Impement the `INotifyPropertyChanged` interface for the ViewModel class. In the setter for all properties in the ViewModel, fire the PropertyChanged event. This way the bindings will be informed whenever the property they are bound to changes... –  May 21 '17 at 00:09

2 Answers2

1

when you assign DataContext, myList is null. When it is created later, property doesn't report about changing (via event)

quick fix is to change the order of operations:

public MainWindow()
{
    myList = new ObservableCollection<MyObject>
    {
      new MyObject() { MyID = "6222" },
      new MyObject() { MyID = "12" },
      new MyObject() { MyID = "666" }
    };
    this.DataContext = this;
    InitializeComponent();
}

also fix column binding (Binding="{Binding MyID}") or property name (MyId) because binding path should match property name

but I suggest to create a separate class (which implements INotifyPropertyChanged) with myList property, and use an instance of that class (view model) to set DataContext of a window.

ASh
  • 34,632
  • 9
  • 60
  • 82
0

Figured it out.

using System;
using System.Windows;
using System.ComponentModel;
using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;

namespace WPFBindingDataGridTest2
{
    public partial class MainWindow : Window
    {
        private ObservableCollection<TestClass> testClass;

        public MainWindow()
        {
            InitializeComponent();

            testClass = new ObservableCollection<TestClass>();
            testClass.Add(new TestClass(NameValue: "John"));
            testClass.Add(new TestClass(NameValue: "Frank"));
            testClass.Add(new TestClass(NameValue: "Sarah"));
            testClass.Add(new TestClass(NameValue: "David"));

            // this.DataContext = this does not appear to be nessecary if it the class is stored in the main window
            dataGrid.ItemsSource = testClass;

        }
    }

    class TestClass : INotifyPropertyChanged
    {
        private string name;

        public TestClass(string NameValue)
        {
            this.Name = NameValue;
        }

        public String Name
        {
            get { return name; }
            set { this.name = value; NotifyPropertyChanged(); }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}

XAML

<Window x:Class="WPFBindingDataGridTest2.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:WPFBindingDataGridTest2"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <DataGrid x:Name="dataGrid" AutoGenerateColumns="False">
            <DataGrid.Columns>
                <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
            </DataGrid.Columns>
        </DataGrid>

    </Grid>
</Window>