简体   繁体   中英

Race condition with INotifyPropertyChanged - c#

my scenario: There are two comboboxes with a bound SelectedItem property. The first combobox contains the costcentres and the second one the employees of the selected costcentre.

That means if SelectedCostcentre changes, INotifyPropertyChanged fires and searches for all employees in the costcentre.

ViewModel:

  public abstract class SelectEmployeeViewModel : ViewModelBase
{
    protected readonly Plant plant;

    public ObservableCollection<Costcentre> Costcentres { get; protected set; }
    public Costcentre SelectedCostcentre { get; set; }
    public ObservableCollection<Employee> Employees { get; protected set; }
    public Employee SelectedEmployee { get; set; }

    public bool CostcentresEnabled
    {
        get { return Costcentres != null && Costcentres.Any(); }
    }
    public bool EmployeesEnabled
    {
        get { return Employees != null && Employees.Any(); }
    }

    protected SelectEmployeeViewModel(Window window, Page page, Plant plant) : base(window, page)
    {
        this.plant = plant;

        PropertyChanged += SelectEmployeeViewModel_PropertyChanged;
        Costcentres = mainController.CostcentreDao.GetByPlant(plant);
    }

    private void SelectEmployeeViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
    {
        switch (e.PropertyName)
        {
            case nameof(SelectedCostcentre):
                SetEmployees();
                break;
        }
    }

    private void SetEmployees()
    {
        if (SelectedCostcentre != null)
            Employees = mainController.EmployeeDao.GetByCostcentre(SelectedCostcentre);
        else
            Employees = new ObservableCollection<Employee>();
    }
}

Xaml:

   <ComboBox
        ItemsSource="{Binding Costcentres}"
        SelectedItem="{Binding SelectedCostcentre}"
        DisplayMemberPath="DisplayName"
        HorizontalAlignment="Left"
        IsEnabled="{Binding CostcentresEnabled}"
        Margin="81,61,0,0" VerticalAlignment="Top" Width="213"/>
    <ComboBox
        ItemsSource="{Binding Employees}"
        SelectedItem="{Binding SelectedEmployee}"
        DisplayMemberPath="DisplayName"
        IsEnabled="{Binding EmployeesEnabled}"
        HorizontalAlignment="Left" Margin="81,88,0,0" VerticalAlignment="Top" Width="213"/>

This works great. Now i build a search function for employees which can find them in all costcentres. If I found one, I need to change the SelecedCostcentre and SelectedEmployee programatically.

Doesn't this create a race condition? Because If I set the SelectedCostcentre property PropertyChanged fires and sets the Employees property.

  private void SetEmployee(Employee employee)
    {
        SelectedCostcentre = Costcentres.Single(x => x.Id == employee.Costcentre.Id);
        SelectedEmployee = Employees.Single(x => x.Id == employee.Id);
    }

How can I solve this without having a race condition?

Thanks

There is no race condition, because the whole thing happens on one thread.

SelectedCostcentre = Costcentres.Single(x => x.Id == employee.Costcentre.Id);

First setter of SelectedCostcentre property is executed, which invokes PropertyChanged (in your code I don't see it, but I assume that's just a typo). This in turn calls SelectEmployeeViewModel_PropertyChanged handler and SetEmployees . So after line above is executed - Employees are populated for given selected Costcenter , synchronously, without any race conditions.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM