Amr Ibrahim
Amr Ibrahim

Reputation: 177

WPF Window DataContext error "invalid column name"

Trynig to set DataContext to WPF Window I am using CodeFirst and here is the code

    public class Employee
{
    [Key]
    public int EmployeeId { get; set; }

    [Display(Name = "FullName")]
    [Required(ErrorMessage = "FullNameRequired")]
    public string FullName { get; set; }

    public string Address { get; set; }

    public string Phone { get; set; }

    public double Salary { get; set; }

    public string Email { get; set; }

    public string Job { get; set; }

}

public class EmployeeVM
{
    SDBContext db = new SDBContext();

    public List<Employee> Employees;

    public EmployeeVM()
    {
        this.Employees= db.Employees.ToList();
    }
}

added the ViewModel to the window datacontext

 xmlns:VM="clr-namespace:Project_Test.ViewModels"

<Window.DataContext>
    <VM:EmployeeVM/>
</Window.DataContext>

But I get the error "invalid column name Job"

and I tried binding 'Employees' Collection to DataGrid but it didn't work

ItemsSource="{Binding Employees}"

Done that in codebehind and it works fine

SDBContext db = new SDBContext();
public MainWindow()
{
    InitializeComponent();

    DG_Employees.ItemsSource = db.Employees.ToList();
}

Update

I deleted the attribute 'Job' and got another error: "the model backing the context has changed since the database was created. consider using code first"

Upvotes: 0

Views: 367

Answers (1)

Shorstok
Shorstok

Reputation: 531

For your first approach to work, your Employees has to be property, not field, like this:

public class EmployeeVM
{
    SDBContext db = new SDBContext();

    public List<Employee> Employees {get;set;}

    public EmployeeVM()
    {
        this.Employees= db.Employees.ToList();
    }
}

Then when you bind ItemsSource to your Employees it should work.

But.

If you plan loading Employees from database somewhere except costructor, your EmployeeVM should implement INotifyPropertyChanged and Employees property should raise PropertyChanged event on change, so your Viewmodel should look like:

public class EmployeeVM : INotifyPropertyChanged
{
    SDBContext db = new SDBContext();

    private List<Employee> _employees;
    public List<Employee> Employees
    {
        get { return _employees; }
        set
        {
            if (Equals(value, _employees)) return;
            _employees = value;
            OnPropertyChanged("Employees");
        }
    }

    public EmployeeVM()
    {
        this.Employees = db.Employees.ToList();
    }


    public event PropertyChangedEventHandler PropertyChanged;

    [NotifyPropertyChangedInvocator]
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }
}

Then, every time you do this.Employees = /..something../ your bound DataGrid should see ItemsSource changed.

But even more, if you plan to let user add/remove Employees from DataGrid or in some other way modify Employees collection , you should change Employees property type from List<Employee> to ObservableCollection<Employee>, and then your View (e.g. DataGrid) should get events whenever new Employee will be removed or added to Employees collection.

And there's more, if you plan changing Employee's properties like FullName etc and want these changes to be noticed by view (e.g. DataGrid to update corresponding cell after Eployee's FullName was changed) your Employee class, in turn, should implement INotifyPropertyChanged too - but even better, you let alone Employee which is a part of Model and loaded from database and create separate viewmodel for Employee class.

I have to add, if your task is only to load Employees from database once on ViewModel construction, get them to View, read-only, no editions, updates or deletions, you could omit all the hassle above, but I think that's a rare scenario.

Upvotes: 0

Related Questions