WPF - 事件/绑定 - 无限循环问题

时间:2015-01-26 03:17:03

标签: wpf wpf-controls

我遇到了一个wpf项目的问题,我正在研究两个控件似乎创建了一个无限循环。

我有两个输入文本框(TextBox1和TextBox2)。当用户在TextBox1中输入数字时,事件将触发计算,然后计算将使用某个值填充TextBox2。 TextBox2也可以接受输入,这将触发反向计算以使用某个值填充TextBox1。

由于这两个事件,当文本输入到TextBox1中时,它似乎触发了一个无限循环,其中每个事件和视图模型的更改都会继续触发另一个。

有谁知道阻止这种情况发生的最佳方法?

以下是一些产生堆栈溢出的示例代码:

代码/ viewmodel:

public partial class HelloWorldView : UserControl, INotifyPropertyChanged {
    public HelloWorldView() {
        InitializeComponent();
        DataContext = this;
    }

    private decimal _fahrenheit = 32;
    public decimal Fahrenheit {
        get { return _fahrenheit; }
        set {
            _fahrenheit = value;
            OnPropertyChanged("Fahrenheit");
            Celsius = _fahrenheit / 2;
        }
    }

    private decimal _celsius;
    public decimal Celsius {
        get { return _celsius; }
        set {
            _celsius = value;
            OnPropertyChanged("Celsius");
        }
    }

    #region PropertyChanged

    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) {
        var handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion

    #region Events

    private void FahrenheitBox_OnTextChanged(object sender, TextChangedEventArgs e) {
        _celsius = Fahrenheit / 2.1m;
        OnPropertyChanged("Celsius");
    }

    private void CelsiusBox_OnTextChanged(object sender, TextChangedEventArgs e) {
        _fahrenheit = Celsius * 1.2m;
        OnPropertyChanged("Fahrenheit");
    }

    #endregion
}     

的Xaml:

<Grid>
    <StackPanel>
        <TextBlock Text="Hello World" Foreground="Green" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Calibri" FontSize="24" FontWeight="Bold"></TextBlock>

        <TextBox Name="FahrenheitBox" Text="{Binding Fahrenheit}" MaxWidth="75" TextChanged="FahrenheitBox_OnTextChanged" />

        <TextBox Name="CelsiusBox" Text="{Binding Celsius}" MaxWidth="75" TextChanged="CelsiusBox_OnTextChanged" />
    </StackPanel>
</Grid>

2 个答案:

答案 0 :(得分:0)

我们的项目中也存在这个问题,你需要停止相互更新,当你从UI设置TextBox1时你的代码不应该调用TextBox2属性的Setter代码,你可以设置该属性的支持字段和单独举起PropertyChanged事件。

编辑除了您在事件处理程序中所做的更改外,请更改您的视图模型代码。这是视图模型属性非常常见的模式,可以防止不必要的事件。

public decimal Fahrenheit 
    {
        get { return _fahrenheit; }
        set {
                if(_fahrenheit == value)
                { 
                    return;
                }
                _fahrenheit = value;
                OnPropertyChanged(); // removed property name , not needed
                //Celsius = _fahrenheit / 2; // removed , allready taken care in event
            }
     }

    private decimal _celsius;
    public decimal Celsius 
    {
        get { return _celsius; }
        set {
                if(_celsius == value)
                {
                    return;
                }     
                _celsius = value;
                OnPropertyChanged(); // removed property name, not needed
             }
    }

答案 1 :(得分:0)

我没有测试过这个,但它应该像这样工作

public partial class HelloWorldView : UserControl, INotifyPropertyChanged {
public HelloWorldView() {
    InitializeComponent();
    DataContext = this;
}

private decimal _fahrenheit = 32;
public decimal Fahrenheit {
    get { return _fahrenheit; }
    set {
         if(_fahrenheit!=value)
       {
        _fahrenheit = value;
        Celsius = _fahrenheit / 2;
        OnPropertyChanged();//there is no need to pass a name, as your
      CallerMemberName deals with it
       }
    }
}

private decimal _celsius;
public decimal Celsius {
    get { return _celsius; }
    set {
        if(_celsius!=value)
       {
        _celsius = value;
        Fahrenheit = Celsius * 1.2m;
        OnPropertyChanged();
      }
    }
}

你根本不需要任何OnTextChanged