0

I'm using WPF and MVVM pattern to develop a desktop application. Maybe I'm not clear about how a DataGrid control would work, but if I modify an item (text, checkbox, etc.), the modification persists even if I don't make any permanent database update (using Entity Framework). For example, I may switch to view different data, and when I come back to view the grid with modified data (but without saving to db), the change is there. Somehow the in-memory data has been changed by the DataGrid control and is not refreshed or synced with database.

In other words, the data in the DataGrid remained modified until I stop and re-run it from visual studio.

  • UPDATED: Another way to ask this question would be: What actually happens when I update, say, an item of a DataGrid? If it is bound to a ViewModel's property P in two-way mode then I suppose P will be updated. But even if I refresh its value (setting the P to null then calling the data access methods again), the modified data are still there.

Does anybody have any idea of what happened?

Thanks!

UPDATED 2: Here is the xaml code which binds a DataGrid to a property named UserList in the ViewModel.

<DataGrid
          x:Name="UserList"
          ItemsSource="{Binding UserList, Mode=TwoWay}"
          AutoGenerateColumns="False"
          AllowDrop="True"
          RowBackground="Orange"
          AlternatingRowBackground="#FFC4B0B0">
  <!-- define columns to view -->
  <DataGrid.Columns>
    ...
  </DataGrid.Columns>
</DataGrid>

Here is the code running in the ViewModel. The method InitialiseData() is called in the constructor of the VM and before I want to do something else with persistent data, so I supposed is always refreshed.

private void InitialiseData()
{
     // Retrieves user list from the business layer's response
     Response userList = _userBL.GetUserList();

 if (userList is FailResponse)
 {
     MessageBox.Show(userList.Message);
     return;
 }
 else
 {
     UserList = null;          
     UserList = (IEnumerable<User>)((SuccessResponse)userList).Data;
 }

** UPDATED 3 **:

private IEnumerable<User> _userList;
public IEnumerable<User> UserList
{
    get
    {
        return _userList;
    }

    set
    {
        _userList = value;
        NotifyOfPropertyChange(() => UserList);
    }
}
tab87vn
  • 389
  • 5
  • 17

1 Answers1

0

If you switch back, you are switching to in-memory collection which was updated by DataGrid before. Or do you load data from dtb again?

EDIT:

Ok, now as you have posted the code, I know where is the problem. DataGrid is not refreshed as I thought. Make sure, you will raise NotifyProperyChanged on the property UserList. Then it will work. See ObservableCollection class as well.

Divisadero
  • 895
  • 5
  • 18
  • Let's say I switch to another View/ViewModel. And when I switch back to the `ViewModel` where the `DataGrid` stays, there's always a `RetrieveData()` method which eventually leads to a `EF` select query. But I suppose that query does not contact the actual database, because db records are intact. – tab87vn Mar 22 '16 at 09:54
  • Well, try to debug, if it really reloads the data. I would say that you do not refresh context and datagrid is connected to previous updated collection. – Divisadero Mar 22 '16 at 09:56
  • I suspect the `DbContext` instance that is created when the application starts up (in a controller's bootstrap), and gets injected into all invoked `ViewModel`. Is it the right way, or should I create a new `DbContext` instance every time I need to use it (e.g. when a View/ViewModel is loaded) – tab87vn Mar 22 '16 at 09:59
  • Sorry, `DbContext` objects are not not injected directly into `ViewModel`, but into business layer (BL) classes, which in turn create DAL objects, which makes use of database, dbset or transaction objects to interact with database. BL objects are injected into `ViewModel` as the applications starts. Something like below: `VM(BL)` -> `BL(dbcontext)` -> `DAL(dbcontext)` -> `EF` -> database – tab87vn Mar 22 '16 at 14:18
  • Ok. Can you post the code how the DataGrid ItemSource is set? Are data refreshed for sure? – Divisadero Mar 22 '16 at 14:26
  • In fact, I've always used raised the `PropertyChanged` event. In this case, I inherit my ViewModel from `Caliburn.Micro`'s `PropertyChangeBase` class, so I suppose there's no problem raising property changed. Pls see the updated code snippet for the VM's property. – tab87vn Mar 23 '16 at 09:06
  • Hm, then, without whole source code I give up, because it should work. I assume you have tried (just to be sure) adding UpdateTrigger = OnPropertyChanged [not sure of exact name]. But it is default on DataGrid I guess... – Divisadero Mar 23 '16 at 09:12
  • In fact, I suppose there's no problem with the binding between DataGrid control and the bound property. The problem, I suppose, is the fact that the DataGrid's inline update does modify the in-memory data source, from which the property fetches its data. Let's say when I switch back to the viewmodel, the property is reassigned with supposedly updated data from database, but somehow in-memory (changed before) and database are not in sync. And by in-line update i mean clicking on the column, modify the value but there's absolutely no database update operation invoked. – tab87vn Mar 23 '16 at 09:27
  • 1
    Have you tried that hypothesis on some simple model? – Divisadero Mar 23 '16 at 09:31
  • Err not yet, I'll try removing different layers and just directly calling from data from ViewModel. – tab87vn Mar 23 '16 at 09:36
  • It is up to you, but I would recommend another project => one file test. – Divisadero Mar 23 '16 at 09:40
  • Hey, it works. Creating a new `DbContext` in the ViewModel and fetching data from it. Works like a charm. This seems to be my vital mistake: use a single `DbContext` instance with global scope (whole application), while it should be used with a smallest scope possible (function). http://stackoverflow.com/questions/34087243/dbcontext-caching/34087303#34087303 – tab87vn Mar 23 '16 at 09:56
  • 1
    Ah, i havent noticed that. Context should be used in using(...){} all the time. Yes. – Divisadero Mar 23 '16 at 10:03
  • So let's say a DAL class has different methods, each will initialise a new `DbContext` instance with the `using` statement that covers a request/transaction. This means a DbContext object is to be used and disposed once the request/transaction is finished. With smallest granularity possible. Correct? – tab87vn Mar 23 '16 at 10:12