private void fireAutomationEvents() { //no reentrancy. It may happen if one of handlers calls UpdateLayout synchronously if (_inFireAutomationEvents) { return; } EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordLayout, EventTrace.Level.Verbose, EventTrace.Event.WClientLayoutFireAutomationEventsBegin); try { _inFireAutomationEvents = true; _firePostLayoutEvents = false; LayoutEventList.ListItem [] copy = AutomationEvents.CopyToArray(); for (int i = 0; i < copy.Length; i++) { LayoutEventList.ListItem item = copy[i]; //store peer here in case if thread gets pre-empted between check for IsAlive and invocation //and GC can run making something that was alive not callable. AutomationPeer peer = null; try { // this will return null if element is already GC'ed peer = (AutomationPeer)(item.Target); } catch (InvalidOperationException) //this will happen if element is being resurrected after finalization { peer = null; } if (peer != null) { peer.FireAutomationEvents(); // if handler dirtied the tree, go clean it again before calling other handlers if (hasDirtiness) { break; } } else { AutomationEvents.Remove(item); } } } finally { _inFireAutomationEvents = false; EventTrace.EasyTraceEvent(EventTrace.Keyword.KeywordLayout, EventTrace.Level.Verbose, EventTrace.Event.WClientLayoutFireAutomationEventsEnd); } }