![](/img/trans.png)
[英]How to the see output from unit-tests in the Test-Result window in VS2010?
[英]Output stream of text to VS2010 Output Window
我為VS2010創建了一個外接程序,該外接程序使用單獨的類進行一些處理。 結果是在“輸出窗口”的新窗格中顯示的文本。
該處理類的構造函數采用對由addins Connect類創建的新OutputWindowPane的引用。 使用OutputString方法寫入文本。
這可以正常工作,並且可以正確顯示文本,但是當執行返回到addins Connect類時,所有這些內容都會在一次更新中顯示。 我還注意到,在外接程序運行時,IDE似乎凍結了。 我是Addin開發的新手,所以錯過了明顯的東西嗎?
有沒有一種方法可以修改此過程,以便在每次調用OutputString時在“輸出窗口”中更新文本? 我希望有某種更新方法,但是我一直找不到。
我注意到,這與使用單獨的類無關。 以下示例說明了我的問題:
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;
}
}
以@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);
}
}
}
這就是我用來在外接程序中寫入OutputWindowPane的內容,它會為每個調用更新文本。 我正在使用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());
}
}
}
}
編輯:我認為您還需要在后台線程上調用OutputWindowPane.OutputString,這是我在調用OutputPane.Write方法時所做的事情。 因此,使用您的代碼將是這樣的:
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.