ObservableCollection中的BlockReentrancy <t> </t>

时间:2011-06-06 02:58:46

标签: c# .net events collections observablecollection

有人可以好心地向我解释BlockReentrancy方法在ObservableCollection<T>中的用途是什么吗?

MSDN显示以下内容作为示例:

//The typical usage is to wrap an OnCollectionChanged call within a using scope, as in the following example:

using (BlockReentrancy())
{
    // OnCollectionChanged call
}

但这似乎并没有为我澄清目的是什么。有人在乎解释吗?

4 个答案:

答案 0 :(得分:26)

ObservableCollection实施INotifyCollectionChanged,因此它有CollectionChanged个事件。如果有此活动的订阅者,他们可以进一步修改集合,同时集合已在通知过程中。由于CollectionChanged事件会记录确切的变化,因此这种互动可能会变得非常混乱。

因此,作为一种特殊情况,ObservableCollection允许CollectionChanged事件的单个订阅者从其处理程序修改集合。但禁止修改CollectionChanged处理程序中的集合,如果有两个或更多订阅者CollectionChanged事件。

方法BlockReentrancyCheckReentancy用于实现此逻辑。在BlockReentrancy方法的开头使用OnCollectionChanged,在修改集合的所有方法中使用CheckReentancy

答案 1 :(得分:11)

这是BlockReentrancy()

的实施
protected IDisposable BlockReentrancy()
{
   this._monitor.Enter();
   return this._monitor;
}

还有另一种方法CheckReentrancy()

protected void CheckReentrancy()
{
    if ((this._monitor.Busy && (this.CollectionChanged != null)) && (this.CollectionChanged.GetInvocationList().Length > 1))
    {
        throw new InvalidOperationException(SR.GetString("ObservableCollectionReentrancyNotAllowed"));
    }
}

ClearItemsInsertItemMoveItemRemoveItemSetItem等方法在修改集合之前检查CheckReentrancy()

因此,下面的代码保证在using内不会更改集合,但只有在有多个处理程序订阅CollectionChanged事件时才会更改。

using BlockReentrancy())
{
    CollectionChanged(this, e);
}

此示例演示了BlockReentrancy()

的效果
private static void Main()
{
    collection.CollectionChanged += CollectionCollectionChanged1;
    collection.CollectionChanged += CollectionCollectionChanged2;
    collection.Add(1);
}

private static void CollectionCollectionChanged1(object sender, NotifyCollectionChangedEventArgs e)
{
    collection.Add(2); // this line will throw exception
}

private static void CollectionCollectionChanged2(object sender, NotifyCollectionChangedEventArgs e)
{
}

答案 2 :(得分:3)

重入是指一个方法直接或间接地执行某些操作,导致再次调用该方法,可能是递归调用。在这种情况下,如果要阻止从处理程序中更改集合,则应在OnCollectionChanged委托内使用using块;试图改变它将引发异常。如果您没有使用它,那么任何修改集合的尝试都会导致再次调用OnCollectionChanged。

答案 3 :(得分:0)

下面是BlockReentrancy之后的code。在ObservableCollection的实现中,每个集合修饰符方法的开始都会调用CheckReentrancy。

    extension ViewControllerName {
      // Put code which you want to 
    }      

   /**
     If you implement UITableViewDataSource and UITableViewDelegate methods 
     or you can implement for UIPickerViewDataSource methods and protocol also    
  */

   extension ViewController: UItableViewDataSource, UITableViewDelegate {

     //implement tableview datasource and delegate method 

   }

      /**
          Keyboard show/hide 
      */  
      extension ViewController {
       /**
           Add scrollview functionality to scroll top and you can call 
           this function from anywhere in the controller.
       */
       func scrollToTop() {

       } 


        @objc func keyboardWasShown(notification: NSNotification)
            {
                var info = notification.userInfo!
                let keyboardSize = (info[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue.size
                let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0, bottom: keyboardSize!.height+10, right: 0.0)
                self.scrolView.contentInset = contentInsets
                self.scrolView.scrollIndicatorInsets = contentInsets
                var aRect : CGRect = self.view.frame
                aRect.size.height -= keyboardSize!.height
                if let activeField = self.activeTextField
                {
                    if (!aRect.contains(activeField.frame.origin))
                    {
                        self.scrolView.scrollRectToVisible(activeField.frame, animated: true)
                    }
                }
            }
            // when keyboard hide reduce height of scroll view
            @objc func keyboardWillBeHidden(notification: NSNotification){
                let contentInsets : UIEdgeInsets = UIEdgeInsets(top: 0.0, left: 0.0,bottom: 0.0, right: 0.0)
                self.scrolView.contentInset = contentInsets
                self.scrolView.scrollIndicatorInsets = contentInsets
                self.view.endEditing(true)
            }
        }

(版权所有(c).NET Foundation和贡献者)