【问题标题】:How can I avoid recursion when updating my ViewModel properties?更新 ViewModel 属性时如何避免递归?
【发布时间】:2009-06-18 14:05:41
【问题描述】:

在我看来,我有一个滑块和一个组合框

当我更改滑块时,我希望组合框发生更改。

当我改变组合框时,我希望滑块改变。

我可以更新一个或另一个,但如果我尝试更新两个,我会收到 StackOverflow 错误,因为一个属性会在无限循环中不断更新另一个。

我尝试过在一个地方完成更新的 Recalculate(),但仍然遇到递归问题。

如何让每个控件在不进行递归的情况下更新另一个控件?

在视图中:

<ComboBox 
    ItemsSource="{Binding Customers}"
    ItemTemplate="{StaticResource CustomerComboBoxTemplate}"
    Margin="20"
    HorizontalAlignment="Left"
    SelectedItem="{Binding SelectedCustomer, Mode=TwoWay}"/>


<Slider Minimum="0" 
        Maximum="{Binding HighestCustomerIndex, Mode=TwoWay}" 
        Value="{Binding SelectedCustomerIndex, Mode=TwoWay}"/>

在 ViewModel 中:

#region ViewModelProperty: SelectedCustomer
private Customer _selectedCustomer;
public Customer SelectedCustomer
{
    get
    {
        return _selectedCustomer;
    }

    set
    {
        _selectedCustomer = value;
        OnPropertyChanged("SelectedCustomer");
        SelectedCustomerIndex = _customers.IndexOf(_selectedCustomer);
    }
}
#endregion

#region ViewModelProperty: SelectedCustomerIndex
private int _selectedCustomerIndex;
public int SelectedCustomerIndex
{
    get
    {
        return _selectedCustomerIndex;
    }

    set
    {
        _selectedCustomerIndex = value;
        OnPropertyChanged("SelectedCustomerIndex");
        SelectedCustomer = _customers[_selectedCustomerIndex];
    }
}
#endregion

【问题讨论】:

    标签: c# wpf mvvm data-binding


    【解决方案1】:

    尝试设置函数,例如:

    public int SelectedCustomerIndex
    {
        get
        {
            return _selectedCustomerIndex;
        }
    
        set
        {
            if (value != _selectedCustomerIndex)
            {
             _selectedCustomerIndex = value;
             OnPropertyChanged("SelectedCustomerIndex");
             SelectedCustomer = _customers[_selectedCustomerIndex];
            }
        }
    }
    

    仅在值发生实际变化时触发事件。这样,对具有相同值的 set 属性的第二次调用不会导致另一个更改事件。

    当然,您也必须为其他属性这样做。

    【讨论】:

    • 当您有触发 PropertyChanged 事件的属性时,通常建议这样做,因为您应该只在属性实际更改时触发该事件。
    • 这是解决问题的非常幼稚的方法(通常)。您不能假设含义之间没有转换,值可能(尤其是在处理实数时)总是与以前不同。虽然,当它起作用时,它会起作用:-)
    • @greenoldman:你知道如何正确处理它吗?我一直在解决这个问题,但它不断地回来。有时我使用一个标志将一个事件源标记为“我是更新的那个”并忽略传入的请求。这似乎也是 hack。
    【解决方案2】:

    这两个属性是相互调用的,因此是递归的。根本与绑定无关。正确的方法是在任一属性更改时相互更改并触发两个属性的更改通知:

        public Customer SelectedCustomer
        {
            get
            {
                return _selectedCustomerIndex;
            }
    
            set
            {
                _selectedCustomer = value;
                _selectedCustomerIndex = _customers.IndexOf(value);
    
                OnPropertyChanged("SelectedCustomer");
                OnPropertyChanged("SelectedCustomerIndex");
            }
        }
    
        public int SelectedCustomerIndex
        {
            get
            {
                return _selectedCustomerIndex;
            }
    
            set
            {
                _selectedCustomerIndex = value;
                _selectedCustomer = _customers[_selectedCustomerIndex];
    
                OnPropertyChanged("SelectedCustomer");
                OnPropertyChanged("SelectedCustomerIndex");
            }
        }
    

    【讨论】:

      猜你喜欢
      • 2013-11-10
      • 2011-03-20
      • 2021-05-13
      • 2011-02-21
      • 1970-01-01
      • 1970-01-01
      • 2011-01-05
      • 2015-05-20
      • 1970-01-01
      相关资源
      最近更新 更多