-1

I have a model called TimeSheetByEmployeeModel that is implemented with INotifyPropertyChanged.

Model:

public class TimeSheetByEmployeeModel:INotifyPropertyChanged
{
    //public string EmpID { get; set; }
    string _EmpID;
    public string EmpID
    {
        get
        {
            return _EmpID;
        }
        set
        {
            if (_EmpID != value)
            {
                _EmpID = value;
                RaisePropertyChange("EmpID");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void RaisePropertyChange(string prop)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(prop));

        }
    }
}

ViewModel:

ObservableCollection<TimeSheetByEmployeeModel> _TimeSheetList = new ObservableCollection<TimeSheetByEmployeeModel>();
public ObservableCollection<TimeSheetByEmployeeModel> TimeSheetList
{
    get
    {
        return _TimeSheetList;
    }
    set
    {                
        _TimeSheetList = value;             
    }
}

View Code-Behind:

public TimeSheetByEmployee()
{
    InitializeComponent();          

    this.DataContext = this;
}

View:

<DataGrid  ItemsSource="{Binding TimeSheetList,UpdateSourceTrigger=PropertyChanged}"
           AutoGenerateColumns="False"
           CanUserAddRows="False"
           x:Name="timesheetgrid"
           HeadersVisibility="All"
           RowHeaderWidth="20">

  <DataGrid.Columns>
    <DataGridTextColumn Binding="{Binding EmpID,UpdateSourceTrigger=PropertyChanged}" 
                    Header="EmpID"
                    IsReadOnly="True"
                    Width="100"/>
  </DataGrid.Columns>  
</DataGrid>

When I click a button inside the View it calls this method:

private void Ok_Click(object sender, RoutedEventArgs e)
{       
    try
    {
        TimeSheetList.Clear();
        string EmployeeID = cboemployee.SelectedValue.ToString();
        TimeSheetList = TimeSheetByEmployeeDataAccessor.GetTimeSheetByEmployee_ByFromTo(dtpfrom.SelectedDate.GetValueOrDefault(), dtpto.SelectedDate.GetValueOrDefault(), EmployeeID);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }          
}

I dynamically changed TimeSheetList and it should reflect in the datagrid. I developed another form using this structure and it worked fine. However, in this form, when I change TimeSheetList it does not update the datagrid.

What have I researched?

Firstly, I bound some data to TimeSheeList in the view constructor and it's shown in the datagrid. So I assumed binding TimeSheetList to the datagrid works.

Secondly, I changed some code in the Button Click Event:

private void Ok_Click(object sender, RoutedEventArgs e)
{       
    try
    {      
        TimeSheetList.RemoveAt(0);
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }          
}

This code is works perfectly and removes the first row in the datagrid. So I assumed the datagrid itemsource is dynamically changing.

But why does it not update with my original code?

More research,

I added code to the button:

timesheetgrid.ItemsSource = TimeSheetList;

I know it will work, and it does, but normally I don't databind to the datagrid in code-behind and I always databind in the XAML. It always works, but why doesn't it work here?

Update

If I add Mode=TwoWay to the ItemsSource databinding in the datagrid in xaml while debugging like this:

<DataGrid  
    ItemsSource="{Binding TimeSheetList,UpdateSourceTrigger=PropertyChanged,Mode=TwoWay}"
    AutoGenerateColumns="False"
    CanUserAddRows="False"
    x:Name="timesheetgrid"
    HeadersVisibility="All"
    RowHeaderWidth="20">

It works and the datagrid shows data. So I saved and restarted the debugging process and it stops working again.

ASh
  • 34,632
  • 9
  • 60
  • 82

1 Answers1

2

this line:

TimeSheetList = TimeSheetByEmployeeDataAccessor.GetTimeSheetByEmployee_ByFromTo(dtpfrom.SelectedDate.GetValueOrDefault(), dtpto.SelectedDate.GetValueOrDefault(), EmployeeID);

creates a new collection and there is no notification in setter about change:

set
{
    _TimeSheetList = value;
}

I suggest to avoid changing collection and add items to existing collection:

var items = TimeSheetByEmployeeDataAccessor.GetTimeSheetByEmployee_ByFromTo(dtpfrom.SelectedDate.GetValueOrDefault(), dtpto.SelectedDate.GetValueOrDefault(), EmployeeID);
TimeSheetList.Clear();
foreach(var item in items)
    TimeSheetList.Add(item);

... or if you prefer to change collection (like it is done now), then raise notification

set
{
    _TimeSheetList = value;
    RaisePropertyChange("TimeSheetList");
}
ASh
  • 34,632
  • 9
  • 60
  • 82
  • Ok i will test and i will let you known.Thanks –  Jan 19 '18 at 08:55
  • I will tested with re-adding `ObservableCollection` by `foreach` loop(There is no `AddRange` in `ObservableCollection`).Its is work.But adding `RaisePropertyChange` in `set` is not work.I am interested adding `RaisePropertyChange` to `set` more than adding by `foreach` loop.Can you explain RaisePropertyChange with full sample code? Thanks you for your help. –  Jan 19 '18 at 09:10
  • 1
    @Loran, do you perhaps have [this issue](https://stackoverflow.com/questions/1644080/why-does-onpropertychanged-not-work-in-code-behind)? sorry about `AddRange`, i have such extension method in my project (which uses `foreach`+`Add()` internally) – ASh Jan 19 '18 at 09:20
  • Ohh,Thanks you for your link,That is really what i want.Now i get all i want. –  Jan 19 '18 at 09:27