示例#1
0
        public void RegisterEventSink(IEnterLeaveListenerEventSink sink)
        {
            var query = from item in EventSinks
                        where item == sink
                        select item;

            if (!query.Any())
            {
                EventSinks.Add(sink);
            }
        }
示例#2
0
        protected virtual void Dispose(bool disposingFrom)
        {
            if (!Atomic(() => CanDispose && !Disposed && !Disposing, () => Disposing = true))
            {
                return;
            }

            ThreadSafe(() => EventSinks.ToList())
            .ForEach(sink => sink.NotifyDisposing(this));

            if (disposingFrom == DisposingFrom_DisposeInterface)
            {
                DisposeManaged();
            }

            DisposeUnmanaged();

            Disposed = true;

            DisposeFinally();

            ThreadSafe(() => EventSinks.ToList())
            .ForEach(sink => sink.NotifyDisposed(this));
        }
示例#3
0
 public void UnadviseDispose(IDisposableEventSink sink)
 {
     ThreadSafe(() => EventSinks.Remove(sink));
 }
示例#4
0
 public void AdviseDispose(IDisposableEventSink sink)
 {
     ThreadSafe(() => EventSinks.Add(sink));
 }
示例#5
0
        public void SetNodes(VsHierarchyNodes nodes, VsHierarchyChanges changes)
        {
            CheckOnUIThread();
            var description = string.Format("SetNodes(node count={0}, added={1}, deleted={2})",
                                            nodes.Count,
                                            (changes == null ? -1 : changes.AddedItems.Count),
                                            (changes == null ? -1 : changes.DeletedItems.Count));

            using (new TimeElapsedLogger(description, InfoLogger.Instance)) {
                // Simple case: empty hiererchy
                if (nodes.RootNode.GetChildrenCount() == 0)
                {
                    if (!ReferenceEquals(nodes, _nodes))
                    {
                        _nodes = nodes;
                        _nodesVersion++;
                    }
                    CloseVsHierarchy();
                    return;
                }

                // Simple case of unknwon changes or hierarchy is not active.
                if (changes == null || !_vsHierarchyActive)
                {
                    // PERF: WE first open the hierarchy with only a single root node,
                    // then we assign the nodes and refresh the root node children.
                    //
                    // This is to workaround a performance issue in Resharper: Resharper
                    // listens to "OnOpenProjects" event and scans the entire hierarchy
                    // (on the UI thread), which can "hang" Visual Studio for seconds. For
                    // example, when opening a Chromium enlistement with about 180,000
                    // files in the VsHierarchy, Resharper takes up to 20 seconds to scan
                    // all elements.
                    //
                    // One side effect is that Resharper won't know of any of the files in
                    // the hierarchy, so they won't show up in various "Navigate To"
                    // windows.
                    OpenVsHierarchy();

                    if (!ReferenceEquals(nodes, _nodes))
                    {
                        _nodes = nodes;
                        _nodesVersion++;
                    }

                    RefreshAll();
                    return;
                }

                Invariants.Assert(_vsHierarchyActive);

                // PERF: Simple case of one of the collection empty, refresh all is
                // faster than individual operations
                if (nodes.IsEmpty || _nodes.IsEmpty)
                {
                    if (!ReferenceEquals(nodes, _nodes))
                    {
                        _nodes = nodes;
                        _nodesVersion++;
                    }
                    RefreshAll();

                    if (_nodes.RootNode.ExpandByDefault)
                    {
                        ExpandNode(_nodes.RootNode);
                    }
                    return;
                }

                // Incremental case: Notify of add/remove items.
                Invariants.Assert(changes != null);

                // Note: We want to avoid calling "OnItemAdded" in "IVsHierarchyEvents"
                // if possible, because it implies making the item visible.
                // "IVsHierarchyEvents" supports a version of "OnItemAdded" with a
                // "ensureVisible" flag.
                var events1     = EventSinks.OfType <IVsHierarchyEvents>().ToList();
                var events2     = events1.OfType <IVsHierarchyEvents2>().ToList();
                var events1Only = events1.Except(events2.OfType <IVsHierarchyEvents>()).ToList();

                // Pass 1: Notify deletion of old items as long as we have the old node
                // collection active. This is safe because the hierarchy host at this
                // point knows only about current nodes, and does not know anything about
                // new nodes. In return, we have not updated out "_nodes" member, so any
                // GetProperty call will return info about current node only.
                foreach (var deleted in changes.DeletedItems)
                {
                    var deletedNode = _nodes.GetNode(deleted);
                    Invariants.Assert(deletedNode != null);
                    Invariants.Assert(deletedNode.Parent != null);
                    if (_logger.LogNodeChangesActivity)
                    {
                        _logger.Log("Deleting node {0,7}-\"{1}\"", deletedNode.ItemId, deletedNode.FullPath);
                    }

                    // PERF: avoid allocation
                    for (var i = 0; i < events1.Count; i++)
                    {
                        events1[i].OnItemDeleted(deletedNode.ItemId);
                    }
                }

                // Pass 2: Notify of node additions. We first need to switch our "_nodes"
                // field to the new node collection, so that any query made by the
                // hierarchy host as a result of add events will be answered with the
                // right set of nodes (the new ones).
                if (!ReferenceEquals(nodes, _nodes))
                {
                    _nodes = nodes;
                    _nodesVersion++;
                }
                foreach (var added in changes.AddedItems)
                {
                    var addedNode             = nodes.GetNode(added);
                    var previousSiblingItemId = addedNode.GetPreviousSiblingItemId();
                    Invariants.Assert(addedNode != null);
                    Invariants.Assert(addedNode.Parent != null);
                    if (_logger.LogNodeChangesActivity)
                    {
                        _logger.Log("Adding node {0,7}-\"{1}\"", addedNode.ItemId, addedNode.FullPath);
                        _logger.Log("   child of {0,7}-\"{1}\"", addedNode.Parent.ItemId, addedNode.Parent.FullPath);
                        _logger.Log(
                            "    next to {0,7}-\"{1}\"",
                            previousSiblingItemId,
                            (previousSiblingItemId != VSConstants.VSITEMID_NIL
                ? nodes.GetNode(previousSiblingItemId).FullPath
                : "nil"));
                    }

                    // PERF: avoid allocation
                    for (var i = 0; i < events1Only.Count; i++)
                    {
                        events1Only[i].OnItemAdded(
                            addedNode.Parent.ItemId,
                            previousSiblingItemId,
                            addedNode.ItemId);
                    }

                    // PERF: avoid allocation
                    for (var i = 0; i < events2.Count; i++)
                    {
                        events2[i].OnItemAdded(
                            addedNode.Parent.ItemId,
                            previousSiblingItemId,
                            addedNode.ItemId,
                            false /* ensure visible */);
                    }
                }
            }
        }