Immediately after successfully binding the EmployeesViewModel to the DataContext page, it is cleared.

ViewModel EmployeesViewModel inherited from BaseViewModel and contains methods for obtaining ObservableCollection<ClinicService.Employee> from WCF:

 public class EmployeesViewModel:BaseViewModel { public ObservableCollection<ClinicService.Employee> Employees{get;set;} public EmployeesViewModel() { } public async void GetEmployees(bool ShowInactive) { Employees = await Data.WCFConnection.GetEmployeesAsync(true); } } 

BaseViewModel itself is a variation of a familiar MVVM singleton inherited from INotifyPropertyChanged

 public class BaseViewModel : INotifyPropertyChanged { private static BaseViewModel instance; public static BaseViewModel Instance { get { if (instance == null) { instance = new BaseViewModel(); } return instance; } } protected void RaisePropertyChanged(string property) { var handler = PropertyChanged; if (handler != null) { handler(this, new PropertyChangedEventArgs(property)); } } public event PropertyChangedEventHandler PropertyChanged; public virtual bool IsValid() { return true; } 

The appointment is as follows:

 public partial class Employees : Page { EmployeesViewModel emv = new EmployeesViewModel(); public Employees() { InitializeComponent(); emv.GetEmployees(true); //emv успешно получил 16 элементов this.DataContext = emv; //emv показывает полученные элементы (их даже видно в DataGrid, если поставить brakepoint) } //emv очищается после окончания метода, несмотря на то, что объявлен в классе ... } 

I will not show the View, because it is clearly not in it.

Q: Why is emv.Employees cleared immediately after completing the page constructor?

PS Intuitively I feel that the joint in the life cycle of the ViewModel ... but I do not see any crime anywhere.

UPD: Corrected Employees ad in EmployeesViewModel

UPD2: Further localization showed that Employees is cleared immediately after running the asynchronous GetEmployees method in EmployeesViewModel , although the inside of the method according to the Employees trace is filled in:

  public async void GetEmployees(bool ShowInactive) { Employees = await Data.WCFConnection.GetEmployeesAsync(true); } 

UPD3: To simplify, I abandoned the BaseModelView class, transferred its functionality to the EmployeesViewModel , which now looks like this:

  public class EmployeesViewModel: INotifyPropertyChanged { private ObservableCollection<ClinicService.Employee> employees; public ObservableCollection<ClinicService.Employee> Employees { get { return this.employees; } set { if (value != this.employees) { this.employees = value; NotifyPropertyChanged(); } } } public EmployeesViewModel() { } public async Task GetEmployees(bool ShowInactive) { employees = await Data.WCFConnection.GetEmployeesAsync(true); } public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged([CallerMemberName] String propertyName = "") { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } private static EmployeesViewModel instance; public static EmployeesViewModel Instance { get { if (instance == null) { instance = new EmployeesViewModel(); } return instance; } } 

Now the problem is that when you call the NotifyPropertyChanged event, the PropertyChanged event always remains null .

The question is closed

The cause of the problem was that the data binding was carried out until the moment they were received in the asynchronous method. Generating an event public event PropertyChangedEventHandler PropertyChanged; upon completion of the asynchronous method in EmployeesViewModel solved the problem:

  public async Task GetEmployees(bool ShowInactive) { employees = await Data.WCFConnection.GetEmployeesAsync(true); NotifyPropertyChanged("Employees"); } 

    1 answer 1

    I think that is not the problem. In EmployeesViewModel Employees is a field, not a property. Binding to fields in WPF does not work.

    Make Employees non-static public field.


    The following error:

     emv.GetEmployees(true); // (1) async-функция this.DataContext = emv; // (2) 

    What's happening? Line (1) starts the async function to get results. At the time this line emv.Empoyees , emv.Empoyees is still null . Then line (2) binds the DataContext . Triggers are triggered; binding is performed on the current Empoyees value - null . After a while, the async function ends, Empoyees non-zero value. But since INotifyPropertyChanged is still not implemented in the new code, no one sees this new value.

    Do it right:

     ObservableCollection<ClinicService.Employee> employees; public ObservableCollection<ClinicService.Employee> Employees { get { return employees; } set { if (value != employees) { employees = value; RaisePropertyChanged(); }} } 

    The fact that the async function is “completed” (that is, the next line started after the function was called) does not mean that the code of the function itself has worked to the end. Your function is most likely await and will end later. (By the way, this is the reason why async void functions are not recommended, use the async Task .)


    By the way, your RaisePropertyChanged method should use the [CallerMemberName] attribute, as, for example, in the example here (see the DemoCustomer class).


    Still wrong. This time, the employees = await Data.WCFConnection.GetEmployeesAsync(true); . Assignment to a field does not generate a PropertyChanged . Replace this with Employees = ...

    • Yes, this is a big mistake, but the matter, oddly enough, is not in it. I changed the EmployeesViewModel field to the property: public ObservableCollection <ClinicService.Employee> Employees {get; set;} but nothing has changed - Anatoly Nikolaev
    • @AnatolyNikolaev: Still wrong. Completed the answer. - VladD
    • Something changed (see UPD3) It is not quite clear how at this stage the setter influences the situation. After all, I get the data right away in a private field, and the DataGrid, in theory, only reads a property through Get. It turns out until I begin to change the values ​​in the DataGrid I don’t need this setter ... - Anatoly Nikolaev
    • @AnatolyNikolaev: Next iteration :) Updated the answer. - VladD
    • one
      @AnatolyNikolaev: Please! - VladD