示例#1
0
        static void RevaluateMethodInheritanceAdornments(InheritanceTracker @this)
        {
            Contract.Requires(@this != null);

            var workingSnapshot = @this._textViewTracker.TextView.TextSnapshot; //Save the current snapshot so it doesn't change while you work, we assume that the snapshot is the same as the source file.

            //Check if model is ready
            var parseTree = @this._textViewTracker.LatestSourceFile == null ? null : @this._textViewTracker.LatestSourceFile.GetParseTree();

            if (parseTree == null || !parseTree.IsModelReady())
            {
                @this._textViewTracker.IsLatestSourceFileStale = true;
                Utilities.Delay(() => ContractsPackageAccessor.Current.AskForNewVSModel(), DelayOnVSModelFailedBeforeTryingAgain);
                return;
            }

            //Collect all the methods in this text view
            var methodCollector = new MethodCollector(workingSnapshot);

            methodCollector.Visit(parseTree.RootNode);
            var methods = methodCollector.GetMethods();

            //Calculate which methods are new
            var newKeys = new List <object>(methods.Keys.Where((k) => !@this._methodKeys.Contains(k)));

            ContractsPackageAccessor.Current.Logger.WriteToLog(String.Format("Found {0} new methods.", newKeys.Count));

            //Update our method keys
            @this._methodKeys.Clear();
            @this._methodKeys.AddAll(methods.Keys);

            ContractsPackageAccessor.Current.QueueWorkItem(() => {
                if (@this._textViewTracker.TextView.IsClosed)
                {
                    return;
                }
                var adornmentKeys = new List <object>(@this._adornmentManager.Adornments.Keys);
                foreach (var key in adornmentKeys)
                {
                    var keyAsString = key as string;
                    if (keyAsString == null)
                    {
                        ContractsPackageAccessor.Current.Logger.WriteToLog("Unexpected: A key in the AdornmentManager wasn't a string! key: " + key.ToString());
                        continue;
                    }
                    if (!@this._methodKeys.Contains(key) && keyAsString.EndsWith(MethodCollector.MethodTagSuffix))
                    {
                        @this._adornmentManager.RemoveAdornment(key);
                        ContractsPackageAccessor.Current.Logger.WriteToLog("Removing obsolete method adornment with tag: " + keyAsString);
                    }
                }
            }, () => @this._textViewTracker.TextView.IsClosed || @this._textViewTracker.TextView.HasAggregateFocus);

            //Create placeholder adornments for our new methods and queue them for contract lookup
            ContractsPackageAccessor.Current.QueueWorkItem(() => {
                foreach (var key in newKeys)
                {
                    MethodDeclarationNode method;
                    if (methods.TryGetValue(key, out method))
                    {
                        ContractsPackageAccessor.Current.Logger.WriteToLog("Creating placeholder adornment and enqueueing for future contract lookup for: " + key.ToString());
                        #region Create placeholder adornment
                        //We add the placeholder adornment here because our workingSnapshot corresponds most closely to the syntactic model's text
                        var snapshotSpan = new SnapshotSpan(method.GetSpan().Convert(workingSnapshot).Start, 1);
                        var trackingSpan = workingSnapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeExclusive);
                        var ops          = AdornmentOptionsHelper.GetAdornmentOptions(ContractsPackageAccessor.Current.VSOptionsPage);
                        @this._adornmentManager.AddAdornment(new InheritanceContractAdornment(trackingSpan, @this._textViewTracker.VSTextProperties, ContractsPackageAccessor.Current.Logger, @this._adornmentManager.QueueRefreshLineTransformer, ops), key);
                        #endregion
                        @this._methodsNeedingContractLookup.Enqueue(new KeyValuePair <object, MethodDeclarationNode>(key, method));
                    }
                }
            });

            //Most likely we've changed something (and this is a pretty cheap call), so let's ask for a refresh
            Utilities.Delay(() => ContractsPackageAccessor.Current.QueueWorkItem(@this._adornmentManager.QueueRefreshLineTransformer), DelayAfterMembersRevalutation);

            //Ask for the new VS model so we can look up contracts
            Utilities.Delay(() => ContractsPackageAccessor.Current.QueueWorkItem(ContractsPackageAccessor.Current.AskForNewVSModel), DelayAfterMembersRevalutation);
        }
示例#2
0
        static void RevaluatePropertyInheritanceAdornments(InheritanceTracker @this)
        {
            Contract.Requires(@this != null);

            var workingSnapshot = @this._textViewTracker.TextView.TextSnapshot; //Save the current snapshot so it doesn't change while you work, we assume that the snapshot is the same as the source file.

            //Check if model is ready
            var parseTree = @this._textViewTracker.LatestSourceFile == null ? null : @this._textViewTracker.LatestSourceFile.GetParseTree();

            if (parseTree == null || !parseTree.IsModelReady())
            {
                @this._textViewTracker.IsLatestSourceFileStale = true;
                Utilities.Delay(() => ContractsPackageAccessor.Current.AskForNewVSModel(), DelayOnVSModelFailedBeforeTryingAgain);
                return;
            }

            //Collect all the properties in this text view
            var propertyCollector = new PropertyCollector(workingSnapshot);

            propertyCollector.Visit(parseTree.RootNode);
            var properties = propertyCollector.GetProperties();

            //Get our property keys
            var keys      = new List <object>();
            var newTuples = new List <Tuple <object, object> >();

            foreach (var tuple in properties.Keys)
            {
                if (tuple.Item1 != null)
                {
                    keys.Add(tuple.Item1);
                }
                if (tuple.Item2 != null)
                {
                    keys.Add(tuple.Item2);
                }
                if (!(@this._propertyKeys.Contains(tuple.Item1) && @this._propertyKeys.Contains(tuple.Item1)))
                {
                    newTuples.Add(tuple);
                }
            }

            ContractsPackageAccessor.Current.Logger.WriteToLog(String.Format("Found {0} new properties.", newTuples.Count));

            //Update our property keys
            @this._propertyKeys.Clear();
            @this._propertyKeys.AddAll(keys);

            ContractsPackageAccessor.Current.QueueWorkItem(() => {
                if (@this._textViewTracker.TextView.IsClosed)
                {
                    return;
                }
                var adornmentKeys = new List <object>(@this._adornmentManager.Adornments.Keys);
                foreach (var key in adornmentKeys)
                {
                    var keyAsString = key as string;
                    if (keyAsString == null)
                    {
                        ContractsPackageAccessor.Current.Logger.WriteToLog("Unexpected: A key in the AdornmentManager wasn't a string! key: " + key.ToString());
                        continue;
                    }
                    if (!@this._propertyKeys.Contains(key) && keyAsString.EndsWith(PropertyCollector.PropertyTagSuffix))
                    {
                        @this._adornmentManager.RemoveAdornment(key);
                        ContractsPackageAccessor.Current.Logger.WriteToLog("Removing obsolete property adornment with tag: " + keyAsString);
                    }
                }
            }, () => @this._textViewTracker.TextView.IsClosed || @this._textViewTracker.TextView.HasAggregateFocus);

            //Create placeholder adornments for our new properties and queue them for contract lookup
            ContractsPackageAccessor.Current.QueueWorkItem(() => {
                foreach (var tuple in newTuples)
                {
                    PropertyDeclarationNode property;
                    if (properties.TryGetValue(tuple, out property))
                    {
                        if (tuple.Item1 != null && tuple.Item2 != null &&
                            property.GetAccessorDeclaration.GetSpan().Start.Line == property.SetAccessorDeclaration.GetSpan().Start.Line)
                        {
                            // set and get on same line, don't add adornment
                            ContractsPackageAccessor.Current.Logger.WriteToLog("Skipping adornments for " + property.GetName(workingSnapshot) + " because get and set are on same line");
                        }
                        else
                        {
                            ContractsPackageAccessor.Current.Logger.WriteToLog("Creating placeholder adornment and enqueueing for future contract lookup for: " + property.GetName(workingSnapshot));
                            if (tuple.Item1 != null)
                            {
                                #region Create getter placeholder adornment
                                ContractsPackageAccessor.Current.Logger.WriteToLog(String.Format("\t(Creating getter placeholder with tag {0})", tuple.Item1));
                                //We add the placeholder adornment here because our workingSnapshot corresponds most closely to the syntactic model's text
                                var snapshotSpan = new SnapshotSpan(property.GetAccessorDeclaration.GetSpan().Convert(workingSnapshot).Start, 1);
                                var trackingSpan = workingSnapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeExclusive);
                                var ops          = AdornmentOptionsHelper.GetAdornmentOptions(ContractsPackageAccessor.Current.VSOptionsPage);
                                @this._adornmentManager.AddAdornment(new InheritanceContractAdornment(trackingSpan, @this._textViewTracker.VSTextProperties, ContractsPackageAccessor.Current.Logger, @this._adornmentManager.QueueRefreshLineTransformer, ops), tuple.Item1);
                                #endregion
                            }
                            if (tuple.Item2 != null)
                            {
                                #region Create setter placeholder adornment
                                ContractsPackageAccessor.Current.Logger.WriteToLog(String.Format("\t(Creating setter placeholder with tag {0})", tuple.Item2));
                                //We add the placeholder adornment here because our workingSnapshot corresponds most closely to the syntactic model's text
                                var snapshotSpan = new SnapshotSpan(property.SetAccessorDeclaration.GetSpan().Convert(workingSnapshot).Start, 1);
                                var trackingSpan = workingSnapshot.CreateTrackingSpan(snapshotSpan.Span, SpanTrackingMode.EdgeExclusive);
                                var ops          = AdornmentOptionsHelper.GetAdornmentOptions(ContractsPackageAccessor.Current.VSOptionsPage);
                                @this._adornmentManager.AddAdornment(new InheritanceContractAdornment(trackingSpan, @this._textViewTracker.VSTextProperties, ContractsPackageAccessor.Current.Logger, @this._adornmentManager.QueueRefreshLineTransformer, ops), tuple.Item2);
                                #endregion
                            }
                            @this._propertiesNeedingContractLookup.Enqueue(new KeyValuePair <Tuple <object, object>, PropertyDeclarationNode>(tuple, property));
                        }
                    }
                }
            });

            //Most likely we've changed something (and this is a pretty cheap call), so let's ask for a refresh
            Utilities.Delay(() => ContractsPackageAccessor.Current.QueueWorkItem(@this._adornmentManager.QueueRefreshLineTransformer, () => @this._textViewTracker.TextView.HasAggregateFocus), DelayAfterMembersRevalutation);

            //Ask for the new VS model so we can look up contracts
            Utilities.Delay(() => ContractsPackageAccessor.Current.QueueWorkItem(ContractsPackageAccessor.Current.AskForNewVSModel, () => @this._textViewTracker.TextView.HasAggregateFocus), DelayAfterMembersRevalutation);
        }
示例#3
0
        void DoWork()
        {
            string  assemblyName;
            Version assemblyVersion;
            string  assemblyLocation;
            string  typeName;
            int     genericParameterCount;

            GetNecessaryInfo(out assemblyName, out assemblyVersion, out assemblyLocation, out typeName, out genericParameterCount);


            #region Create host
            var host = this._projectTracker.Host;

            if (host == null)
            {
                VSServiceProvider.Current.Logger.WriteToLog("Couldn't create host.");
                return;
            }
            #endregion
            #region Find and load assembly
            IAssembly iAssembly = null;

            if (assemblyName.Equals(host.CoreAssemblySymbolicIdentity.Name.Value, StringComparison.OrdinalIgnoreCase) && assemblyVersion.Equals(host.CoreAssemblySymbolicIdentity.Version))
            {
                iAssembly = host.FindAssembly(host.CoreAssemblySymbolicIdentity);
            }
            else
            {
                var references = _projectTracker.References;
                VSLangProj.Reference reference   = null;
                var assemblyNameWithoutExtension = Path.GetFileNameWithoutExtension(assemblyName);
                for (int i = 1; i <= references.Count; i++)//TODO: Unify this code. This process of looking up a reference from a name is also done in ContractsProvider.TryGetAssemblyReference
                {
                    var    tempRef = references.Item(i);
                    string refName = tempRef.Name;
                    if (refName.Equals(assemblyNameWithoutExtension, StringComparison.OrdinalIgnoreCase))
                    {
                        reference = tempRef;
                        break;
                    }
                }
                if (reference != null)
                {
                    IName   iName    = host.NameTable.GetNameFor(Path.GetFileNameWithoutExtension(reference.Path));
                    string  culture  = reference.Culture;
                    Version version  = new Version(reference.MajorVersion, reference.MinorVersion, reference.BuildNumber, reference.RevisionNumber);
                    string  location = reference.Path;
                    var     tempRef2 = new Microsoft.Cci.Immutable.AssemblyReference(host, new AssemblyIdentity(iName, culture, version, Enumerable <byte> .Empty, location));
                    iAssembly = host.LoadAssembly(tempRef2.AssemblyIdentity);
                }
                else
                {
                    VSServiceProvider.Current.Logger.WriteToLog("Couldn't find reference for metadata file.");
                    return;
                }
            }
            if (iAssembly == null || iAssembly == Dummy.Assembly)
            {
                VSServiceProvider.Current.Logger.WriteToLog("Couldn't get assembly for metadata file.");
                return;
            }
            #endregion
            #region Get contracts provider
            var contractsProvider = host.GetContractExtractor(iAssembly.UnitIdentity);
            if (contractsProvider == null)
            {
                VSServiceProvider.Current.Logger.WriteToLog("Couldn't get contracts provider.");
                return;
            }
            #endregion
            #region Collect contracts
            var type = UnitHelper.FindType(host.NameTable, iAssembly, typeName, genericParameterCount);
            if (type == null || type is Dummy)
            {
                VSServiceProvider.Current.Logger.WriteToLog("Couldn't find metadata type '" + typeName + "' in assembly.");
                return;
            }

            //This dictionaries will map the method/property signature to the contracts for the method/property
            var methodsToContracts = new Dictionary <string, IMethodContract>(type.Methods.Count());
            var gettersToContracts = new Dictionary <string, IMethodContract>();
            var settersToContracts = new Dictionary <string, IMethodContract>();

            //Set the formatting options for property getters and setters
            var propertySignatureFormattingOptions = NameFormattingOptions.OmitContainingNamespace |
                                                     // NameFormattingOptions.ReturnType |
                                                     NameFormattingOptions.TypeParameters |
                                                     NameFormattingOptions.UseTypeKeywords |
                                                     NameFormattingOptions.OmitContainingType;
            //NameFormattingOptions.Visibility;
            //Set the formating options for methods
            var methodSignatureFormattingOptions = NameFormattingOptions.OmitContainingNamespace |
                                                   NameFormattingOptions.ReturnType |
                                                   NameFormattingOptions.ParameterName |
                                                   NameFormattingOptions.ParameterModifiers |
                                                   NameFormattingOptions.TypeParameters |
                                                   NameFormattingOptions.UseTypeKeywords |
                                                   NameFormattingOptions.OmitContainingType |
                                                   //NameFormattingOptions.Modifiers |
                                                   NameFormattingOptions.Signature
                                                   //NameFormattingOptions.Visibility
            ;

            //var sourceEmitterOutput = new SourceEmitterOutputString();//TODO: Use source emitter for all my printing? Instead of the whole NameFormattingOptions ordeal.
            //var csSourceEmitter = new SourceEmitter(sourceEmitterOutput);

            foreach (var method in type.Methods)
            {
                var methodContract = ContractHelper.GetMethodContractForIncludingInheritedContracts(host, method);
                if (methodContract != null && methodContract != ContractDummy.MethodContract)
                {
                    if (IsGetter(method))
                    {
                        if (method.ParameterCount > 0) //We have an indexer!
                        {
                            var indexerSignature = PrintIndexer(method, true);
                            gettersToContracts.Add(indexerSignature, methodContract);
                        }
                        else
                        {
                            var getterSignature = MemberHelper.GetMemberSignature(method, propertySignatureFormattingOptions);//Example: "XmlSchemaSet Schemas.get"
                            getterSignature = getterSignature.Substring(0, getterSignature.LastIndexOf('.'));
                            gettersToContracts.Add(getterSignature, methodContract);
                        }
                    }
                    else if (IsSetter(method))
                    {
                        if (method.ParameterCount > 1) //We have an indexer!
                        {
                            var indexerSignature = PrintIndexer(method, false);
                            settersToContracts.Add(indexerSignature, methodContract);
                        }
                        else
                        {
                            var setterSignature = MemberHelper.GetMemberSignature(method, propertySignatureFormattingOptions);
                            setterSignature = setterSignature.Substring(0, setterSignature.LastIndexOf('.'));
                            settersToContracts.Add(setterSignature, methodContract);
                        }
                    }
                    else
                    {
                        //#region Print method, stolen from CSharpSourceEmitter
                        //csSourceEmitter.PrintMethodDefinitionVisibility(method);
                        //csSourceEmitter.PrintMethodDefinitionModifiers(method);

                        //bool conversion = csSourceEmitter.IsConversionOperator(method);
                        //if (!conversion) {
                        //  csSourceEmitter.PrintMethodDefinitionReturnType(method);
                        //  if (!method.IsConstructor && !csSourceEmitter.IsDestructor(method))
                        //    csSourceEmitter.PrintToken(CSharpToken.Space);
                        //}
                        //csSourceEmitter.PrintMethodDefinitionName(method);
                        //if (conversion)
                        //  csSourceEmitter.PrintMethodDefinitionReturnType(method);

                        //if (method.IsGeneric) {
                        //  csSourceEmitter.Traverse(method.GenericParameters);
                        //}
                        //csSourceEmitter.Traverse(method.Parameters);
                        //#endregion
                        //var methodSignature = sourceEmitterOutput.Data;
                        //sourceEmitterOutput.ClearData();
                        var methodSignature = MemberHelper.GetMemberSignature(method, methodSignatureFormattingOptions);//Example: "XmlAttribute CreateAttribute(string name)"
                        methodsToContracts.Add(methodSignature, methodContract);
                    }
                }
            }
            #endregion

            var hasMethodContracts   = methodsToContracts.Count > 0;
            var hasPropertyContracts = gettersToContracts.Count > 0 || settersToContracts.Count > 0;

            if (!hasMethodContracts && !hasPropertyContracts)
            {
                VSServiceProvider.Current.Logger.WriteToLog("No contracts found.");
                return;
            }

            int propertyCounter = 0; //Counts the number of adornments added for property contracts
            int methodCounter   = 0; //Counts the number of adornments added for method contracts
            foreach (var line in _textView.TextSnapshot.Lines)
            {
                var lineText = line.GetText();

                //Skip lines with comments
                //This assumes that no method/property decelerations in metadata files will have comments in them
                if (lineText.Contains("//"))
                {
                    continue;
                }

                // bail out on nested types
                var typeNameMatch = Regex.Match(lineText, @"(class|struct|interface|enum) (\w+)");
                if (typeNameMatch.Success)
                {
                    if (typeNameMatch.Groups[2].Value == type.Name.Value)
                    {
                        continue;
                    }
                    break;
                }

                if (hasPropertyContracts &&
                    lineText.Contains('{') && (lineText.Contains(" get; ") || lineText.Contains(" set; ")) && lineText.Contains('}')) //Check if line is a property decleration
                {
                    #region Add property contracts
                    //Parse the property decleration to get a signature we can compare to our contract dictionaries
                    //Example of a property decleration: "     public int Build { get; }"
                    int  endOfSig              = lineText.IndexOf('{') - 1;
                    int  startOfSig            = endOfSig - 1;
                    bool hasHitSpace           = false;
                    bool isInPropertyParameter = false;
                    for (int i = startOfSig; i > 0; i--)
                    {
                        char c = lineText[i];
                        if (c == ']')
                        {
                            isInPropertyParameter = true;
                        }
                        else if (c == '[')
                        {
                            isInPropertyParameter = false;
                        }
                        else if (hasHitSpace && c == ' ')
                        {
                            startOfSig = i + 1;
                            break;
                        }
                        else if (!isInPropertyParameter && c == ' ')
                        {
                            startOfSig = i + 1;
                            break; // MAF: ignore return type of properties.
                            //hasHitSpace = true;
                        }
                    }
                    var propertySignature = lineText.Substring(startOfSig, endOfSig - startOfSig); //Example: "int Build"

                    IMethodContract getterContract = null;
                    IMethodContract setterContract = null;
                    if (gettersToContracts.TryGetValue(propertySignature, out getterContract) | // yes eager evaluation!!!
                        settersToContracts.TryGetValue(propertySignature, out setterContract))
                    {
                        var tag = propertySignature.GetHashCode();//We use this to uniquely identify the particular method/property decleration

                        //Find this first non-whitespace character. This is were we'll place the adornment.
                        int firstNonWhitespace = 0;
                        for (int i = 0; i < lineText.Length; i++)
                        {
                            char c = lineText[i];
                            if (c != ' ')
                            {
                                firstNonWhitespace = i;
                                break;
                            }
                        }
                        var span = _textView.TextSnapshot.CreateTrackingSpan(line.Start + firstNonWhitespace, propertySignature.Length, SpanTrackingMode.EdgeExclusive);
                        _vsTextProperties.LineHeight = _textView.LineHeight;
                        var ops       = AdornmentOptionsHelper.GetAdornmentOptions(VSServiceProvider.Current.VSOptionsPage);
                        var adornment = new MetadataContractAdornment(span, _vsTextProperties, VSServiceProvider.Current.Logger, _adornmentManager.QueueRefreshLineTransformer, ops);
                        adornment.SetContracts(getterContract, setterContract, null /* "Contracts from " + typeName + "." */);
                        _adornmentManager.AddAdornment(adornment, tag);
                        propertyCounter++;
                    }
                    #endregion
                    continue;
                }
                if (hasMethodContracts &&
                    lineText.Contains('(') && lineText.Contains(')') && lineText.Contains(';')) //Check if line is a method decleration
                {
                    #region Add method contracts
                    //Parse the method decleration to get a signature we can compare to our contract dictionaries
                    //Example of a method decleration: "      public static Version Parse(string input);"
                    int endOfSig = lineText.LastIndexOf(')') + 1;
                    //int startOfSig = !Char.IsWhiteSpace(lineText[0]) ? 0 : lineText.IndexOf(lineText.First(c => !Char.IsWhiteSpace(c)));
                    //int startOfSig = lineText.IndexOf('(');
                    //bool hitSpace = false;
                    //for (int i = startOfSig; i > 0; i--) {
                    //  char c = lineText[i];
                    //  if (c == ' ' && hitSpace) {
                    //    startOfSig = i + 1;
                    //    break;
                    //  } else if (c == ' ') {
                    //    hitSpace = true;
                    //  }
                    //}
                    var methodSignature = lineText.Substring(0, endOfSig); //Example: "Version Parse(string input)"

                    // remove modifiers
                    methodSignature = Regex.Replace(methodSignature, modifierFilter, "");
                    methodSignature = methodSignature.Trim();
                    if (methodSignature.StartsWith(type.Name.Value + "("))
                    {
                        methodSignature = "void .ctor" + methodSignature.Substring(type.Name.Value.Length);
                    }
                    IMethodContract methodContract;
                    if (methodsToContracts.TryGetValue(methodSignature, out methodContract))
                    {
                        var tag = methodSignature.GetHashCode();//We use this to uniquely identify the particular method/property decleration

                        //Find this first non-whitespace character. This is were we'll place the adornment.
                        int firstNonWhitespace = 0;
                        for (int i = 0; i < lineText.Length; i++)
                        {
                            char c = lineText[i];
                            if (c != ' ')
                            {
                                firstNonWhitespace = i;
                                break;
                            }
                        }
                        var span = _textView.TextSnapshot.CreateTrackingSpan(line.Start + firstNonWhitespace, methodSignature.Length, SpanTrackingMode.EdgeExclusive);
                        _vsTextProperties.LineHeight = _textView.LineHeight;
                        var ops       = AdornmentOptionsHelper.GetAdornmentOptions(VSServiceProvider.Current.VSOptionsPage);
                        var adornment = new MetadataContractAdornment(span, _vsTextProperties, VSServiceProvider.Current.Logger, _adornmentManager.QueueRefreshLineTransformer, ops);
                        adornment.SetContracts(methodContract, "Contracts from " + typeName + ".");
                        _adornmentManager.AddAdornment(adornment, tag);
                        //if (methodContract.IsPure) {
                        //  var purityAdornment = new PurityAdornment(_vsTextProperties, adornment);
                        //  //_adornmentManager.AddAdornment(purityAdornment, null);
                        //}
                        methodCounter++;
                    }
                    #endregion
                    continue;
                }
            }

            #region Add button to collapse all contracts
            if (propertyCounter > 0 || methodCounter > 0)
            {
                var button = new Button();
                button.Content = "Hide all contracts";
                button.Click  += OnCollapseAllClick;
                button.Cursor  = Cursors.Hand;
                var collapseAllAdornment = new StaticAdornment(false, 10d, true, 10d, button);
                _adornmentManager.AddStaticAdornment(collapseAllAdornment);
            }
            #endregion
        }