【问题标题】:update dependency of a property in loops更新循环中属性的依赖关系
【发布时间】:2013-05-31 07:09:47
【问题描述】:

我有一个 foreach 循环,我在其中更新对象的属性。这个属性有一个依赖项,我在 setter 中更新它。这似乎减慢了我的应用程序,因为依赖项需要一些时间,并且在 foreach 循环之后只需更新一次。

不建议在循环之后调用依赖的更新,因为我的代码中很多其他地方都用到了setter。除此之外,对象应该负责更新它的依赖而不是调用函数。

为了清晰起见的代码示例

//anywhere else in my other classes
private Foo[] objects;

public void UpdateFoo()
{
  //update propably hundrets of small objects
  foreach (Foo obj in objects)
  {
    obj.Property = 1;
  }
}

class Foo
{
  private int _property;
  public int Property 
  { 
    get { return _property; } 
    set
    {
      _property = value;

      //Update something anywhere else
      StaticBigFoo.Update();
    } }
}

class StaticBigFoo
{
  public static void Update()
  {
    //do something longer
  }
}

我想知道这个场景的最佳做法是什么?

  • 我可以使用DependencyProperty,它是PropertyChanged-Callback,但是每次仍然会更新依赖项。
  • 我曾想过在 Dispatcher 中使用 DispatcherPriority.Background 开始一些东西,然后过滤它以区分不同的代表(但如何?)
  • 我可以使用一些事务逻辑,但我不知道在那里使用什么。我读过一些关于TransactionScope 的文章,我可以用它来做类似的事情吗?

【问题讨论】:

    标签: c# wpf callback


    【解决方案1】:

    您可以使用由几个 GUI 元素提供的 BeginUpdate()EndUpdate() 调用定义的部分。我的意思是这样的:

    class Foo
    {
      private int _property;
      public int Property 
      { 
        get { return _property; } 
        set
        {
          _property = value;
    
          if(inUpdate)
            propertyChanged = true;
          else
            //Update something anywhere else
            StaticBigFoo.Update();
        } }
    
        static bool inUpdate = false;
        static bool propertyChanged;
        public static void BeginUpdate() { inUpdate = true; propertyChanged = false; }
        public static void EndUpdate() { inUpdate = false; if(propertyChanged) StaticBigFoo.Update(); }
    }
    

    然后

    Foo.BeginUpdate();    
    foreach (Foo obj in objects)
    {
      obj.Property = 1;
    }
    Foo.EndUpdate();
    

    这允许在需要时推迟更新。

    【讨论】:

    • 我想我需要一些类似事务的东西,比如 Begin() 和 End(),不过我会像 denis morozov 所说的那样重写我的 setter 以保持它的干净。我会接受这个,太糟糕了,我不能接受你两个答案的合并版本;-)
    【解决方案2】:

    只是一个思考的食物,属性主要用于以受控方式获取/设置字段的值。或者在您的情况下,多走一英里就是更改通知。可以说,可以进行验证,延迟加载。但似乎你在二传手中做的比这多得多,我不是最佳实践。为什么,因为我们可能会更频繁地访问属性,这会导致对属性进行评估,从而导致底层逻辑。

    【讨论】:

      【解决方案3】:

      我会让 setter 保持干净,在他们中只做字段分配和 PropertyChanged。然后听 PropertyChanged 并在那里做额外的事情(如果你愿意,可以在一个单独的线程中 - 为了简单起见,在这里使用任务);

      class Foo
      {
       //constructor
       public Foo()
       {
          PropertyChanged += (s,args) =>
          {
             switch(args.PropertyName)
             {
                case "Property" :
                  Task.Factory.StartNew(() => { StaticBigFoo.Update();});
                  break;
               ....
      
       public int Property
       { get ...
       {
         set  
         {
            if(_property == value) return;
            _property = value;
            RaisePropertyChanged(() => Property);
          ......
      

      【讨论】:

      • 我喜欢这个,但它会在每次属性更改时调用 Update,尽管它是在一个新任务中。
      • 另一个想法,如果你不喜欢听所有的属性改变。如何创建一个特定的私人事件“UpdateStaticBigFoo”,在你的财产中提出它并听它。同样的想法,除了现在它只在该属性改变时触发一次
      猜你喜欢
      • 2014-05-27
      • 1970-01-01
      • 2016-01-04
      • 2014-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-13
      相关资源
      最近更新 更多