【问题标题】:Propertychanged event firing even when property value not changed即使属性值未更改,也会触发 Propertychanged 事件
【发布时间】:2014-04-08 18:03:42
【问题描述】:

我将属性绑定到 WPF 中的控件。通过 while 循环中的递归方法分配/更改属性的值。因此,值的分配速率约为 1 ms。大多数时候值根本没有改变,但是 setter 中的 propertychanged 事件即使在属性值没有改变的情况下也会触发。 我在想属性设置器应该在字段的值发生变化时引发事件。这是我的代码的简化版本:

public sealed class FX : System.ComponentModel.INotifyPropertyChanged 
{
   public event PropertyChangedEventHandler PropertyChanged;
   public void OnPropertyChanged(string PropertyName)
   {
      PropertyChangedEventHandler handler = PropertyChanged;
      if (handler != null)
      {
         handler(this, new PropertyChangedEventArgs(PropertyName));
      }
   }

   private bool _someBool1 = false;
   public bool SomeBool1
   {
       get { return _someBool1; }
       set
       {
          _someBool1 = value;
           OnPropertyChanged("SomeBool1");

           //MessageBox.Show("SomeBool1 : propertychanged event fired!");
       }
   }
}

根据http://www.codemag.com/Article/0907101 UI 是 PropertyChanged 事件的消费者。虽然许多属性的值是不断且尽可能快地分配的,但这可能会导致不必要的 UI 开销。可以放置 OnPropertyChanged("SomeBool2");在 if 语句中? :

private bool _someBool2 = false;
public bool SomeBool2
{
    get { return _someBool2; }
    set
    {
         bool _someBool2OldValue = _someBool2;
         _someBool2 = value;

         if (_someBool2 != _someBool2OldValue)
         {
             OnPropertyChanged("SomeBool2");
             //MessageBox.Show("SomeBool2 : propertychanged event fired!");
         }
     }
}

我是否误解了“属性值更改时触发事件”的想法,或者我的代码实现有误?

【问题讨论】:

  • 嗯..看起来不错。您不需要 _someBool2OldValue 因为您可以询问 if(_someBool2 != value) {...} 但其余看起来不错嗯...

标签: c# wpf properties inotifypropertychanged


【解决方案1】:

我无法想象,someBool2OldValue 的这些东西是用来做什么的:

set
{
     if (_someBool2 != value)
     {
         _someBool2 == value;
         OnPropertyChanged("SomeBool2");
     }
 }

此外,如果您正在运行一些循环,这会使您的视图模型发生频繁的属性更改,那么完全停止触发 PropertyChanged 事件是有意义的:

protected bool StopFiringPropertyChanged { get; set; }

protected virtual void OnPropertyChanged(string propertyName)
{
    if (StopFiringPropertyChanged) 
    {
        return;
    }

    // fire event
}

只有在所有属性的循环完成后才触发它,可以在循环期间更改:

private void SomeMethodWithRecursiveLoop()
{
    StopFiringPropertyChanged = true;
    try
    {
         // do the work
    }
    finally
    {
        StopFiringPropertyChanged = false;
        OnPropertyChanged("SomeProperty1");
        OnPropertyChanged("SomeProperty2");
        OnPropertyChanged("SomeProperty3");
    }   
}

【讨论】:

  • someBool2OldValue 旨在不触发 OnPropertyChanged("SomeBool2");和其他可能的代码,当属性值没有真正改变时。 IE。当递归代码连续多次分配相同的值时。
  • @as74: if (_someBool2 != value) 做同样的事情。您不需要缓存旧值。
【解决方案2】:

是的,在您的第一个示例中,无论何时调用该属性设置器,它都会执行其中的任何代码,包括您的 OnPropertyChanged 处理程序,而不会产生偏见。在属性的 setter/getter 中包含您认为合适的任何条件逻辑是完全有效的。这就是属性优于字段的优点,因为您可以决定任何您喜欢的细节,该值如何响应数据更改,无论是只读还是只写,随心所欲。

对于第二个示例,您可以只使用“值”关键字而不是创建特定字段。

【讨论】:

    猜你喜欢
    • 2011-02-08
    • 2011-12-23
    • 2013-03-08
    • 2022-11-24
    • 1970-01-01
    • 1970-01-01
    • 2013-03-29
    • 1970-01-01
    • 2011-02-13
    相关资源
    最近更新 更多