有人可以好心地向我解释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
}
但这似乎并没有为我澄清目的是什么。有人在乎解释吗?
答案 0 :(得分:26)
ObservableCollection
实施INotifyCollectionChanged
,因此它有CollectionChanged
个事件。如果有此活动的订阅者,他们可以进一步修改集合,同时集合已在通知过程中。由于CollectionChanged
事件会记录确切的变化,因此这种互动可能会变得非常混乱。
因此,作为一种特殊情况,ObservableCollection
允许CollectionChanged
事件的单个订阅者从其处理程序修改集合。但禁止修改CollectionChanged
处理程序中的集合,如果有两个或更多订阅者到CollectionChanged
事件。
方法BlockReentrancy
和CheckReentancy
用于实现此逻辑。在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"));
}
}
ClearItems
,InsertItem
,MoveItem
,RemoveItem
,SetItem
等方法在修改集合之前检查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和贡献者)