Состояние гонки с INotifyPropertyChanged - С#

мой сценарий: есть два поля со списком со связанным свойством SelectedItem. Первый список содержит центры затрат, а второй — сотрудников выбранного центра затрат.

Это означает, что если SelectedCostcentre изменяется, INotifyPropertyChanged увольняет и ищет всех сотрудников в МВЗ.

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"/>

Это прекрасно работает. Теперь я создаю функцию поиска сотрудников, которая может найти их во всех центрах затрат. Если я его нашел, мне нужно программно изменить SelecedCostcentre и SelectedEmployee.

Не создает ли это состояние гонки? Потому что, если я устанавливаю свойство SelectedCostcentre, PropertyChanged срабатывает и устанавливает свойство Employees.

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

Как я могу решить эту проблему, не имея состояния гонки?

Спасибо


person Thomas Klammer    schedule 13.04.2018    source источник
comment
race-comndition — неправильное имя, это однопоточный. Однако у вас может быть каскадное и, возможно, циклическое срабатывание событий. Будьте ясны в том, что вы наблюдаете.   -  person Henk Holterman    schedule 13.04.2018


Ответы (1)


Условий гонки нет, потому что все происходит в одном потоке.

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

Выполняется первый сеттер свойства SelectedCostcentre, который вызывает PropertyChanged (в вашем коде я его не вижу, но предполагаю, что это просто опечатка). Это, в свою очередь, вызывает обработчик SelectEmployeeViewModel_PropertyChanged и SetEmployees. Итак, после выполнения строки выше - Employees заполняются для заданных выбранных Costcenter, синхронно, без каких-либо условий гонки.

person Evk    schedule 13.04.2018
comment
о приятно, спасибо. PropertyChanged находится в ViewModelBase, поэтому вы его не видите. - person Thomas Klammer; 13.04.2018
comment
Да, но я вижу SelectedCostcentre, и у него есть установщик по умолчанию (только set), хотя я ожидал, что он что-то сделает в этом установщике, чтобы вызвать событие изменения свойства. Но, возможно, вы используете что-то вроде Fody или Postsharp, чтобы автоматически сделать это за вас. - person Evk; 13.04.2018
comment
Я использую Fody.PropertyChanged. Он создает сеттер во время сборки - person Thomas Klammer; 13.04.2018