-1

Whats wrong in my data binding ?

I am MVVM beginner and i have to take some data from user in textbox and then display that data in data grid, there are 3 textboxes and corresponding 3 textboxes respectively. And a button which on click must save the entered data to the data grid columns.

I have everything working except the data is not updated to datagrid.

Here is my View:

 < Window x: Class = "DatagRidBelowTextUpdate.MainWindow"
xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns: x = "http://schemas.microsoft.com/winfx/2006/xaml"
Title = "MainWindow"
Height = "350"
Width = "525" >
    < Grid >
    < Grid.RowDefinitions >
    < RowDefinition > < /RowDefinition> < RowDefinition Height = "30" > < /RowDefinition> < RowDefinition > < /RowDefinition> < /Grid.RowDefinitions> < Grid Grid.Row = "0" >
    < Grid.RowDefinitions >
    < RowDefinition > < /RowDefinition> < RowDefinition > < /RowDefinition> < RowDefinition > < /RowDefinition> < /Grid.RowDefinitions> < Grid.ColumnDefinitions >
    < ColumnDefinition > < /ColumnDefinition> < ColumnDefinition > < /ColumnDefinition> < /Grid.ColumnDefinitions> < TextBox Grid.Column = "1"
Grid.Row = "0"
Text = "{Binding EditModel.TextName}"
Height = "20"
Width = "80"
HorizontalAlignment = "Center" > < /TextBox> < TextBox Grid.Column = "1"
Grid.Row = "1"
Text = "{Binding EditModel.RollNumber}"
Height = "20"
Width = "80" > < /TextBox> < TextBox Grid.Column = "1"
Grid.Row = "2"
Text = "{Binding EditModel.Class}"
Height = "20"
Width = "80" > < /TextBox> < Label Grid.Row = "0"
HorizontalAlignment = "Center"
VerticalAlignment = "Center" > Name < /Label> < Label Grid.Row = "1"
HorizontalAlignment = "Center"
VerticalAlignment = "Center" > RollNumber < /Label> < Label Grid.Row = "2"
HorizontalAlignment = "Center"
VerticalAlignment = "Center" > Class < /Label> < /Grid> < Grid Grid.Row = "1" >
    < Button Width = "80"
Height = "20"
Command = "{Binding SaveStudentRecord}" > Save < /Button> < /Grid> < Grid Grid.Row = "2" >
    < DataGrid ItemsSource = "{Binding DGrid}" >
    < DataGrid.Columns >
    < DataGridTextColumn Header = "Name"
Binding = "{Binding  DgName, Mode=TwoWay}"
Width = "150" > < /DataGridTextColumn> < DataGridTextColumn Header = "Rollnumber"
Binding = "{Binding DgRollnumber, Mode=TwoWay}"
Width = "150" > < /DataGridTextColumn> < DataGridTextColumn Header = "Class"
Binding = "{Binding DgClass , Mode=TwoWay}"
Width = "150" > < /DataGridTextColumn> < /DataGrid.Columns> < /DataGrid> < /Grid> < /Grid> < /Window>

My ViewModel:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;

namespace DatagRidBelowTextUpdate {
    class ViewModel {
        private RelayCommand saveStudentRecord;
        private Model editModel;
        public bool canExecute {
            get;
            set;
        }
        public ObservableCollection < Model > DGrid;
        private string dgName;
        private string dgRollnumber;
        private string dgClass;
        public string DgName {
            get {
                return dgName;
            }
            set {
                dgName = value;
                PropertyChangedEventArgs("DgName");
            }
        }
        public string DgRollnumber {
            get {
                return dgRollnumber;
            }
            set {
                dgRollnumber = value;
                PropertyChangedEventArgs("DgRollnumber");
            }
        }
        public string DgClass {
            get {
                return dgClass;
            }
            set {
                dgClass = value;
                PropertyChangedEventArgs("DgClass");
            }
        }

        public Model EditModel {
            get {
                return editModel;
            }
            set {
                editModel = value;
                PropertyChangedEventArgs("EditModel");
            }
        }

        public ViewModel() {
            editModel = new Model();
            canExecute = true;
            DGrid = new ObservableCollection < Model > ();
        }
        public RelayCommand SaveStudentRecord {
            get {
                return saveStudentRecord = new RelayCommand(() => MyAction(), canExecute);
            }
        }

        private void MyAction() {
            string chck1 = editModel.TextName; //TextName; //I see on debugging that TextName contains the text entered so how to add this text to Datagrid column
            string chck2 = editModel.Class;
            string chck3 = editModel.RollNumber;
            //  DGrid = new ObservableCollection<Model>();
            //    dgClass = editModel.Class;
            //    dgName = editModel.TextName;
            //    dgRollnumber = editModel.RollNumber;
            DGrid.Add(editModel);
            //   editModel = new Model();

        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void PropertyChangedEventArgs(string propertyName) {
            if (PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

My Model:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace DatagRidBelowTextUpdate {
    class Model {
        private string textName;
        private string rollNumber;
        private string cclass;

        public string TextName {
            get {
                return textName;
            }
            set {
                textName = value;
                PropertyChangedEventArgs("TextName");
            }
        }

        public string RollNumber {
            get {
                return rollNumber;
            }
            set {
                rollNumber = value;
                PropertyChangedEventArgs("RollNumber");
            }
        }

        public string Class {
            get {
                return cclass;
            }
            set {
                cclass = value;
                PropertyChangedEventArgs("Class");
            }
        }
        public event PropertyChangedEventHandler PropertyChanged;
        private void PropertyChangedEventArgs(string propertyName) {
            if (PropertyChanged != null) {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

What is wrong in the binding that it do not update the datagrid in button click MyAction()

EDIT: (I dont want to use DGrid.Add(editModel); and i dont want to do AutoGenrateColumns to True, because o have to understand the binding concept of individual UI).I mean i wish to bind the columns in datagrid manually in xaml and then assign the textboxes data using textbox binded variables to the datagrid binded variables, i mean something like dgName=editModel.Name on button click. Viem Model is:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;

namespace DatagRidBelowTextUpdate
{
    class ViewModel :INotifyPropertyChanged
    {
        private RelayCommand saveStudentRecord;
        private Model editModel;
        public bool canExecute { get; set; }
        public ObservableCollection<Model> DGrid { get; set; }
        private string dgName{ get; set; }
        private string dgRollnumber { get; set; }
        private string dgClass { get; set; }


        public string DgName
        {
            get
            {
                return dgName;
            }
            set
            {
                dgName = value;
                PropertyChangedEventArgs("DgName");
            }
        }
        public string DgRollnumber
        {
            get
            {
                return dgRollnumber;
            }
            set
            {
                dgRollnumber = value;
                PropertyChangedEventArgs("DgRollnumber");
            }
        }
        public string DgClass
        {
            get
            {
                return dgClass;
            }
            set
            {
                dgClass = value;
                PropertyChangedEventArgs("DgClass");
            }
        }

        public Model EditModel
        {
            get
            {
                return editModel;
            }
            set
            {
                editModel = value;
                PropertyChangedEventArgs("EditModel");
            }
        }

        public ViewModel()
        {
            editModel = new Model();
            canExecute = true;
        }
        public RelayCommand SaveStudentRecord
        {
            get { return saveStudentRecord = new RelayCommand(() => MyAction(), canExecute); }
        }

        private void MyAction()
        {
           dgClass = editModel.Class;
            dgName = editModel.TextName;
           dgRollnumber = editModel.RollNumber;
            //according to my understanding , the data in editModel.Class must be added to dgClass in View, obsolutley i am wrong, please correct me.
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void PropertyChangedEventArgs(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

View is:

<Window x:Class="DatagRidBelowTextUpdate.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="30"></RowDefinition>
            <RowDefinition></RowDefinition>
        </Grid.RowDefinitions>
        <Grid Grid.Row="0">
            <Grid.RowDefinitions>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
                <RowDefinition></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition></ColumnDefinition>
                <ColumnDefinition></ColumnDefinition>
            </Grid.ColumnDefinitions>
            <TextBox Grid.Column="1" Grid.Row="0" Text="{Binding EditModel.TextName}" Height="20" Width="80" HorizontalAlignment="Center"></TextBox>
            <TextBox Grid.Column="1" Grid.Row="1" Text="{Binding EditModel.RollNumber}"  Height="20" Width="80"></TextBox>
            <TextBox Grid.Column="1" Grid.Row="2" Text="{Binding EditModel.Class}" Height="20" Width="80"></TextBox>
            <Label Grid.Row="0" HorizontalAlignment="Center" VerticalAlignment="Center">Name</Label>
            <Label Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center">RollNumber</Label>
            <Label Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center">Class</Label>
        </Grid>
        <Grid Grid.Row="1" >
            <Button Width="80" Height="20" Command="{Binding SaveStudentRecord}">Save</Button>
        </Grid>
        <Grid Grid.Row="2">
            <DataGrid ItemsSource="{Binding DGrid, Mode=TwoWay}" AutoGenerateColumns="False">
                <DataGrid.Columns>
                    <DataGridTextColumn Header="Name" Binding="{Binding DgName}" Width="150"></DataGridTextColumn>
                    <DataGridTextColumn Header="Rollnumber" Binding="{Binding DgRollnumber}" Width="150"></DataGridTextColumn>
                    <DataGridTextColumn Header="Class" Binding="{Binding DgClass}"  Width="150"></DataGridTextColumn>
                </DataGrid.Columns>
            </DataGrid>
        </Grid>
    </Grid>
</Window>

1 Answers1

0

First make sure that the ViewModel is set as the DataContext of your window. You can test by checking if the Commands that you created are being called when you click the Save button. You can check this link out to validate that.

Also change DGrid into a property. Because currently it is defined as a variable. Change

    public ObservableCollection<Model> DGrid;

to

    public ObservableCollection<Model> DGrid {get; set;}

and that should work! Hope that helps!

Community
  • 1
  • 1
Andrei dela Cruz
  • 628
  • 4
  • 11
  • I changed code to this : public ObservableCollection DGrid { get; set; } but the output is bit unexpected , please see : I was expecting soem other columns to update but it adds some other 3 columns rather then existing-Binded three columns http://prntscr.com/9vdbtf – traps traps Jan 27 '16 at 06:24
  • Also i dont understand why there are 6 columns, instead of 3 – traps traps Jan 27 '16 at 06:30
  • Hi you could either set DataGrid's AutoGenerateColumns property to false and fix the Column bindings or remove the pre-defined column bindings and allow the Grid to generate the columns for you. The properties that are bound in the XAML seems to be different than what you defined in the Model class. – Andrei dela Cruz Jan 27 '16 at 06:39
  • @Andreia Thanks, I remobed all bindings from xaml for datagrid, and i set AutoGenerateColumns to false, not it gives empty columns, it do nto add data to grind and it do nto show header name of columns, please see http://prntscr.com/9vdja5 – traps traps Jan 27 '16 at 06:57
  • Oh sorry removing column header was by my mistaek removing from xaml. sorry. – traps traps Jan 27 '16 at 07:01
  • So it's working now? Great! Please do accept my answer! Thanks in advance! – Andrei dela Cruz Jan 27 '16 at 07:03
  • No, it is giving the header but not printing in the string in i entered in textboxes. – traps traps Jan 27 '16 at 07:07
  • Make sure that the ItemsSource for the DataGrid is defined – Andrei dela Cruz Jan 27 '16 at 07:09
  • And when i set AutoGenerateColumns property to false it just add the next row to datagrid but empty, but when i make the same property to true then it shows 6 columns and last 3 are updated with the text entered, but why it show 6 columns , should be 3 only. – traps traps Jan 27 '16 at 07:14
  • Remove all the column definitions when using AutoGenerateColumns to true. Just like what i said in the previous statement. If you are going to define the columns, I checked the code and saw that in the XAML file you bound it to DgName but in the Model class, the property is called "Name" without the "Dg" – Andrei dela Cruz Jan 27 '16 at 07:17
  • And when i debug editModel , inside MyAction() then i get PropertyCganged=Null, rest the variables i can see the same which i entered teh data in textboxes. What could eb the reason of this strange behavior – traps traps Jan 27 '16 at 07:18
  • You need to implement INotifyPropertyChanged to the ViewModel too – Andrei dela Cruz Jan 27 '16 at 07:19
  • the bindign with "Dg" represents the binding for each column in data grid, whereas th binding without "Dg" in Model is fro the 3 text boxes, My approach is first get the entered data through the bindign doen in Model classes for textboxes and assign to the datagrid by doing something like "DgName= EditModel.Name" , and i want to do with AutoGenerateColumns =true so that i learn doing individual bindings of UI in MVVM – traps traps Jan 27 '16 at 07:23
  • Hello bro, I have udated the View and ViewModel, please have a look at edit part. – traps traps Jan 27 '16 at 07:30
  • Hi it looks good but if AutoGenerateColumns is set to true then you do not need to define the "columns" on your own. So if you want this approach to work you should delete the WHOLE node Also, the binding in the column SHOULD be the same as the properties that you defined in the Model or else xaml won't be able to find those. And yes, the bindings for the textbox and the datagrid columns should point to the same properties. – Andrei dela Cruz Jan 27 '16 at 07:33
  • @Andrie, i wish to do by AutoGenerateColumns =False, i am really very sorry for misunderstanding, and for that i need to have all 3 bindings in my datagrid for each columns and also 3 bindings for textboxes. And after what should i do ? Please help me .. – traps traps Jan 27 '16 at 07:46
  • it could work for me, But i really wanna learn how to do the bindings of textboxes and Daragrid columns in case if i have to do AutoGenerateColumns=False. I would really appreciate if you ediit the answer and let me know how to do it so that it would nto only be helpful for me, but also for every one who see it. I mark your answer but really appreciate if you do the requested. – traps traps Jan 27 '16 at 08:03
  • Just change GdName to Name and do that for all the other bindings inside the grid – Andrei dela Cruz Jan 27 '16 at 08:22