【问题标题】:Race condition with INotifyPropertyChanged - c#INotifyPropertyChanged 的​​竞争条件 - c#
【发布时间】:2018-04-13 05:38:47
【问题描述】:

我的场景:有两个组合框绑定了SelectedItem 属性。 第一个组合框包含成本中心,第二个组合框包含所选成本中心的员工。

这意味着如果SelectedCostcentre 发生变化,INotifyPropertyChanged 会触发并搜索成本中心的所有员工。

视图模型:

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

这很好用。 现在我为员工建立了一个搜索功能,可以在所有成本中心找到他们。如果我找到了,我需要以编程方式更改SelecedCostcentreSelectedEmployee

这不会造成竞争条件吗?因为如果我设置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);
    }

如何在没有竞争条件的情况下解决这个问题?

谢谢

【问题讨论】:

  • race-comndition 是错误的名称,这是单线程的。不过,您可能会触发级联事件,也可能触发循环事件。清楚你所观察到的。

标签: c# race-condition inotifypropertychanged


【解决方案1】:

没有竞争条件,因为整个事情发生在一个线程上。

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

SelectedCostcentre 属性的第一个 setter 被执行,它调用 PropertyChanged(在你的代码中我没有看到它,但我认为这只是一个错字)。这反过来又调用SelectEmployeeViewModel_PropertyChanged 处理程序和SetEmployees。因此,在执行上述行之后 - 为给定的选定 Costcenter 同步填充 Employees,没有任何竞争条件。

【讨论】:

  • 哦,太好了,谢谢。 PropertyChanged 在 ViewModelBase 中,因此您看不到它。
  • 是的,但我可以看到SelectedCostcentre,它具有默认设置器(只是set),而我希望它在该设置器中执行某些操作以引发属性更改事件。但也许你会使用 Fody 或 Postsharp 之类的东西自动为你做这件事。
  • 我正在使用 Fody.PropertyChanged。它确实在构建时创建了设置器
猜你喜欢
  • 2013-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-20
  • 2022-01-23
  • 2018-10-08
相关资源
最近更新 更多