Get the current filename from a Visual Studio text

2020-07-09 03:38发布

问题:

I'm new to VS extension development. I'm currently working with the text adornment sample in VS 2015 and have been able to get coloured boxes showing correctly. Now I want to extend the sample so the adornment only appears on certain file names.

Googling has said I can use ITextDocumentFactoryService.TryGetTextDocument interface with the IWpfTextView.TextBuffer property to get a filename. This sounds great. But I can't seem to actually get the interface.

In my class I have:

    [Import]
    public ITextDocumentFactoryService TextDocumentFactoryService = null;

But it is always NULL.

How can I get ITextDocumentFactoryService?

namespace Test
{
    internal sealed class TestAdornment
    {
        [Import]
        public ITextDocumentFactoryService TextDocumentFactoryService = null;

        public TestAdornment(IWpfTextView view)
        {
        }

        /// <summary>
        /// Adds the scarlet box behind the 'a' characters within the given line
        /// </summary>
        /// <param name="line">Line to add the adornments</param>
        private void CreateVisuals(ITextViewLine line)
        {
            // TextDocumentFactoryService is NULL
        }
    }
}

回答1:

TextAdornmentTextViewCreationListener.cs

[Export(typeof(IWpfTextViewCreationListener))]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Document)]
internal sealed class TextAdornmentTextViewCreationListener : IWpfTextViewCreationListener
{
    [Import]
    public ITextDocumentFactoryService textDocumentFactory { get; set; }

    //...

    public void TextViewCreated(IWpfTextView textView)
    {
        new TextAdornment(textView, textDocumentFactory);
    }
}

TextAdornment.cs

internal sealed class TextAdornment
    {
        private readonly ITextDocumentFactoryService textDocumentFactory;
        private ITextDocument TextDocument;

        //...    

        public TextAdornment(IWpfTextView view, ITextDocumentFactoryService textDocumentFactory)
        {
            //...

            this.textDocumentFactory = textDocumentFactory;

            //...
        }

     internal void OnLayoutChanged(object sender, TextViewLayoutChangedEventArgs e)
        {
            var res = this.textDocumentFactory.TryGetTextDocument(this.view.TextBuffer, out this.TextDocument);
            if (res)
            {
                //this.TextDocument.FilePath;
            }
            else
            {
                //ERROR
            }
        }
    }


回答2:

You got it via dependency injection.

As you only submitted 2 lines of code I suppose your context is set up, either explicitly by you, either implicitly by some environment who calls your code.

  • You should declare property instead of field
  • It should be public

Then automagically big brother will set it for you before you first access to it.

...or...

You can use constructor injection instead. Note: It is not you who will create your class.

private readonly ITextDocumentFactoryService _textDocumentFactoryService;

[ImportingConstructor]
internal YourClass(ITextDocumentFactoryService textDocumentFactoryService)
{
    _textDocumentFactoryService = textDocumentFactoryService;
}


回答3:

So in my case I needed to put the import statement into the AdornmentTextViewCreationListener. This implements IWpfTextViewCreationListener and is the one with the following decorating the class.

[Export(typeof(IWpfTextViewCreationListener))]
[ContentType("text")]
[TextViewRole(PredefinedTextViewRoles.Document)]

Then I can add

private readonly ITextDocumentFactoryService _textDocumentFactoryService;
[ImportingConstructor]

to my class



标签: c# mef