简体   繁体   English

将文本流输出到VS2010输出窗口

[英]Output stream of text to VS2010 Output Window

I've created an addin for VS2010 that uses a separate class to do some processing. 我为VS2010创建了一个外接程序,该外接程序使用单独的类进行一些处理。 The result of this is text that is displayed in a new pane in the Output Window. 结果是在“输出窗口”的新窗格中显示的文本。

The constructor of this processing class takes a reference to a new OutputWindowPane which is created by the addins Connect class. 该处理类的构造函数采用对由addins Connect类创建的新OutputWindowPane的引用。 Text is written using the OutputString method. 使用OutputString方法写入文本。

This works and text is displayed correctly, however, it is all displayed in one update when execution returns to addins Connect class. 这可以正常工作,并且可以正确显示文本,但是当执行返回到addins Connect类时,所有这些内容都会在一次更新中显示。 I also notice that the IDE seems to freeze while the addin is running. 我还注意到,在外接程序运行时,IDE似乎冻结了。 I'm new to addin development, so have I missed something obvious? 我是Addin开发的新手,所以错过了明显的东西吗?

Is there a way I can modify this process to have the text update in the Output Window with each call of OutputString? 有没有一种方法可以修改此过程,以便在每次调用OutputString时在“输出窗口”中更新文本? I was hoping for an update method of some kind, but I've been unable to find it. 我希望有某种更新方法,但是我一直找不到。

Update 更新资料

I noticed that this has nothing to do with using a separate class. 我注意到,这与使用单独的类无关。 The following example illustrates my problem: 以下示例说明了我的问题:

using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;

namespace MyAddin4
{
    public class Connect : IDTExtensibility2, IDTCommandTarget
    {
       public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
        {
            _applicationObject = (DTE2)application;
            _addInInstance = (AddIn)addInInst;
            if(connectMode == ext_ConnectMode.ext_cm_UISetup)
            {
                object []contextGUIDS = new object[] { };
                Commands2 commands = (Commands2)_applicationObject.Commands;
                string toolsMenuName = "Tools";
            CommandBar menuBarCommandBar = ((CommandBars)_applicationObject.CommandBars)["MenuBar"];
            CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
                CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;
            try
                {
                    Command command = commands.AddNamedCommand2(_addInInstance, "MyAddin4", "MyAddin4", "Executes the command for MyAddin4", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);
                    if((command != null) && (toolsPopup != null))
                    {
                        command.AddControl(toolsPopup.CommandBar, 1);
                    }
                }
                catch(ArgumentException) {}
            }
        }

      public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom) {}

        public void OnAddInsUpdate(ref Array custom) {}

        public void OnStartupComplete(ref Array custom) {}

        public void OnBeginShutdown(ref Array custom) {}

        public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)
        {
            if(neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
            {
                if(commandName == "MyAddin4.Connect.MyAddin4")
                {
                    status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported|vsCommandStatus.vsCommandStatusEnabled;
                    return;
                }
            }
        }

        public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
        {
            handled = false;
            if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
            {
                if(commandName == "MyAddin4.Connect.MyAddin4")
                {
               OutputWindow outputWindow = (OutputWindow) _applicationObject.Windows.Item(Constants.vsWindowKindOutput).Object;
                   OutputWindowPane outputPane = outputWindow.OutputWindowPanes.Add("Processor");
               for (int i = 0; i < 10; i++)
               {
                  System.Threading.Thread.Sleep(500);
                  outputPane.Activate();
                  outputPane.OutputString(i + "\n");
               }
                    handled = true;
                    return;
                }
            }
        }
        private DTE2 _applicationObject;
        private AddIn _addInInstance;
    }
}

Solution

Building on the answer from @ShellShock this is the solution that works for me: 以@ShellShock的答案为基础,这是对我有效的解决方案:

using System;
using Extensibility;
using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.CommandBars;

namespace MyAddin4
{
   public class Connect : IDTExtensibility2, IDTCommandTarget
   {
      public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
      {
         _applicationObject = (DTE2)application;
         _addInInstance = (AddIn)addInInst;
         if(connectMode == ext_ConnectMode.ext_cm_UISetup)
         {
            object []contextGUIDS = new object[] { };
            Commands2 commands = (Commands2)_applicationObject.Commands;
            string toolsMenuName = "Tools";
            CommandBar menuBarCommandBar = ((CommandBars)_applicationObject.CommandBars)["MenuBar"];
            CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
            CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;
            try
            {
               Command command = commands.AddNamedCommand2(_addInInstance, "MyAddin4", "MyAddin4", "Executes the command for MyAddin4", true, 59, ref contextGUIDS, (int)vsCommandStatus.vsCommandStatusSupported+(int)vsCommandStatus.vsCommandStatusEnabled, (int)vsCommandStyle.vsCommandStylePictAndText, vsCommandControlType.vsCommandControlTypeButton);
               if((command != null) && (toolsPopup != null))
               {
                  command.AddControl(toolsPopup.CommandBar, 1);
               }
            }
            catch(ArgumentException) {}
         }
      }

      public void OnDisconnection(ext_DisconnectMode disconnectMode, ref Array custom) {}

      public void OnAddInsUpdate(ref Array custom) {}

      public void OnStartupComplete(ref Array custom) {}

      public void OnBeginShutdown(ref Array custom) {}

      public void QueryStatus(string commandName, vsCommandStatusTextWanted neededText, ref vsCommandStatus status, ref object commandText)
      {
         if(neededText == vsCommandStatusTextWanted.vsCommandStatusTextWantedNone)
         {
            if(commandName == "MyAddin4.Connect.MyAddin4")
            {
               status = (vsCommandStatus)vsCommandStatus.vsCommandStatusSupported|vsCommandStatus.vsCommandStatusEnabled;
               return;
            }
         }
      }

      public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
      {
         handled = false;
         if(executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
         {
            if(commandName == "MyAddin4.Connect.MyAddin4")
            {
               OutputWindow outputWindow = (OutputWindow) _applicationObject.Windows.Item(Constants.vsWindowKindOutput).Object;
               OutputWindowPane outputPane = outputWindow.OutputWindowPanes.Add("Processor");
               Worker workerObject = new Worker(ref outputPane);
               uint loops = 10;
               System.Threading.Thread thread = new System.Threading.Thread(delegate() { workerObject.DoWork(loops); }); 
               thread.Start();
               handled = true;
               return;
            }
         }
      }

      private DTE2 _applicationObject;
      private AddIn _addInInstance;
   }

   public class Worker
   {
      private EnvDTE.OutputWindowPane _pcLintOutputWindowPane;

      public Worker(ref EnvDTE.OutputWindowPane pcLintOutputWindowPane)
      {
         _pcLintOutputWindowPane = pcLintOutputWindowPane;
      }

      public void DoWork(uint loops)
      {
         for (int i = 0; i < loops; i++)
         {
            System.Threading.Thread.Sleep(500);
            WriteText(i + "\n");
         }       
      }

      private void WriteText(string stringToWrite)
      {
         _pcLintOutputWindowPane.Activate();
         _pcLintOutputWindowPane.OutputString(stringToWrite);
      }
   }
}

This is what I use to write to an OutputWindowPane in my addin, and it updates the text for each call. 这就是我用来在外接程序中写入OutputWindowPane的内容,它会为每个调用更新文本。 I'm using VS2008, I don't know if it works differently in VS2010. 我正在使用VS2008,我不知道它在VS2010中是否有不同的工作方式。

public class OutputPane
{
    public string Name { get; private set; }

    private OutputWindowPane _outputWindowPane;
    private static object _outputWindowPaneLock = new object();

    public OutputPane(string name)
    {
        Name = name;
    }

    public void Write(string text)
    {
        CreateOutputPane(Name); // Creates the OutputWindowPane if it does not already exist.

        if (_outputWindowPane != null)
        {
            try
            {
                _outputWindowPane.Activate();
                _outputWindowPane.OutputString(text);
            }
            catch (Exception ex1)
            {
                System.Diagnostics.Debug.WriteLine("Exception writing text '" + text + "': " + ex1.ToString());
                // Exceeded maximum output pane size?
                try
                {
                    _outputWindowPane.Clear();
                    _outputWindowPane.OutputString(text);
                }
                catch (Exception ex2)
                {
                    System.Diagnostics.Debug.WriteLine("Exception writing text '" + text + "': " + ex2.ToString());
                }
            }
        }
    }

Edit: I think you also need to call OutputWindowPane.OutputString on a background thread, which is what I do when I call my OutputPane.Write method. 编辑:我认为您还需要在后台线程上调用OutputWindowPane.OutputString,这是我在调用OutputPane.Write方法时所做的事情。 So using your code, it will be something like this: 因此,使用您的代码将是这样的:

public void Exec(string commandName, vsCommandExecOption executeOption, ref object varIn, ref object varOut, ref bool handled)
{
    handled = false;
    if (executeOption == vsCommandExecOption.vsCommandExecOptionDoDefault)
    {
        if (commandName == "MyAddin4.Connect.MyAddin4")
        {
            OutputWindow outputWindow = (OutputWindow)_applicationObject.Windows.Item(Constants.vsWindowKindOutput).Object;
            OutputWindowPane outputPane = outputWindow.OutputWindowPanes.Add("Processor");
            System.Threading.Thread thread = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(OutputStringThread));
            thread.Start(outputPane);
            handled = true;
            return;
        }
    }
}

private void OutputStringThread(object obj)
{
    try
    {
        OutputWindowPane outputPane = (OutputWindowPane)obj;
        for (int i = 0; i < 10; i++)
        {
            System.Threading.Thread.Sleep(500);
            outputPane.Activate();
            outputPane.OutputString(i + "\n");
        }
    }
    catch (Exception ex)
    {
        // Handle exception
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM