Visual Studio-在调试时将多行表达式插入监视窗口

11
在Visual Studio中调试时,我该如何将多行表达式插入到“监视窗口”中,以便每行不会被分成单独的无效观察表达式。这真的很令人沮丧,因为我有许多跨越多行的表达式需要监视。请注意,“固定到源代码”和“立即窗口”都不能用于跟踪源代码中多个位置的多个值。例如:
PyFunc1(Py.kw("var1", var1),
        Py.kw("var2", var2))

被打破成:

PyFunc1(Py.kw("var1", var1),

Py.kw("var2", var2))

1
你为什么不能在将表达式粘贴到监视窗口之前删除换行符呢? - Cameron
1
尝试将内容粘贴到即时窗口中。对于较长的表达式,这种方法往往效果更好。 - Patrick Nelson - MSFT
1
看看OzCode的魔法一瞥功能 - 它可以显示表达式的结果,即使没有观察或立即窗口。 - Aleksey L.
1
奇怪的是,快速监视命令正常工作。 - Ivan Stoev
1
@denfromufa,我很乐意这样做,但不幸的是,尽管“快速查看”正确显示了表达式和列表中的值,但“表达式”组合框仅显示第一行,更重要的是,“添加监视”按钮或列表项上下文菜单均无法使用 - 它们在监视窗口中产生相同的多行错误。一致性问题 :( - Ivan Stoev
显示剩余6条评论
2个回答

9

复现

我认为这并不是“按设计”,它只是“开箱即用”不可用。

我同意,将多行调用添加到监视窗口中,使用行终止符而不是换行符会更好:

enter image description here


研究

我在这个类似的问题中找到了一些“解决方法”可供选择:

我还在MSDN论坛中找到了此评论

恐怕这是不支持的,我们通常一个一个地编辑。也许您可以提交此功能请求:http://visualstudio.uservoice.com/forums/121579-visual-studio


自己编写Visual Studio Add-In

所以我自己试了一下,这绝不是生产代码,但它向您展示了如何做到这一点:

(单击图像以放大)

enter image description here

namespace AddinMultiLineWatch
{
public class Connect : IDTExtensibility2, IDTCommandTarget
{
    //ADD THESE MEMBER VARIABLES
    //private DebuggerEvents _debuggerEvents = null;
    //private _dispDebuggerEvents_OnEnterBreakModeEventHandler DebuggerEvents_OnEnterBreakMode;
    private Window _watchWindow = null;
    private CommandEvents _objCommandEvents;
    private bool _isRecursive = false;
    public Connect()
    {
    }

    public void OnConnection(object application, ext_ConnectMode connectMode, object addInInst, ref Array custom)
    {
        _applicationObject = (DTE2)application;
        _addInInstance = (AddIn)addInInst;

        //SET THE MEMBER VARIABLES
        //_debuggerEvents = _applicationObject.Events.DebuggerEvents;
        //_debuggerEvents.OnEnterBreakMode += new _dispDebuggerEvents_OnEnterBreakModeEventHandler(BreakHandler);
        //var watchWindow = _applicationObject.Windows.Item(EnvDTE.Constants.vsWindowKindWatch);
        _objCommandEvents = _applicationObject.Events.CommandEvents;
        _objCommandEvents.BeforeExecute += new _dispCommandEvents_BeforeExecuteEventHandler(BeforeExecute);

        if(connectMode == ext_ConnectMode.ext_cm_UISetup)
        {
            object []contextGUIDS = new object[] { };
            Commands2 commands = (Commands2)_applicationObject.Commands;
            string toolsMenuName = "Tools";

            Microsoft.VisualStudio.CommandBars.CommandBar menuBarCommandBar = ((Microsoft.VisualStudio.CommandBars.CommandBars)_applicationObject.CommandBars)["MenuBar"];
ar:
            CommandBarControl toolsControl = menuBarCommandBar.Controls[toolsMenuName];
            CommandBarPopup toolsPopup = (CommandBarPopup)toolsControl;

            try
            {
                Command command = commands.AddNamedCommand2(_addInInstance, "AddinMultiLineWatch", "AddinMultiLineWatch", "Executes the command for AddinMultiLineWatch", 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(System.ArgumentException)
            {
            }
        }
    }

    //ADD THIS METHOD TO INTERCEPT THE DEBUG.ADDWATCH COMMAND
    public void BeforeExecute(string Guid, int ID, object CustomIn, object CustomOut, ref bool CancelDefault)
    {
        EnvDTE.Command objCommand = default(EnvDTE.Command);
        try
        {
            objCommand = _applicationObject.Commands.Item(Guid, ID);
        }
        catch (Exception ex)
        {
        }

        if ((objCommand != null))
        {
            if (objCommand.Name == "Debug.AddWatch")
            {
                //if (_isRecursive) return;
                //_isRecursive = true;
                TextSelection selection = (TextSelection)_applicationObject.ActiveDocument.Selection;
                //TODO make selection goto next semi-colon/Line Terminator...
                var selText = selection.Text;  

                if (string.IsNullOrEmpty(selText)) return;   
                //Only intercept multi-line Add Watch commands                    
                if (selText.Contains(Environment.NewLine))
                {
                  //THE BLACK MAGIC: make it fit in one line! lol
                  selText = selText.Replace(Environment.NewLine, string.Empty);              
                  //THIS CALL IS RECURSIVE, I'LL LEAVE IT TO THE READER AS AN EXERCISE TO SOLVE..
                _applicationObject.ExecuteCommand("Debug.AddWatch", selText);
               }
            }
        }
    }
  1. Create a New Project > Other Project Types > Extensibility > Visual Studio Add-In > name it AddinMultiLineWatch

  2. Go through the wizard

  3. Add the code above to the Connect.cs class - see my //UPPERCASE comments with what stuff to add.

  4. Put a break point on the line TextSelection selection = (TextSelection)_applicationObject.ActiveDocument.Selection;

  5. Press F5 and a new instance of VS will launch > choose New Project > Console App > name it TestMultilineAddWatch

  6. In the program.cs of the Console App, specify a code call over 2 lines and put a break point on it, as shown in the screenshot, eg:

    Add(1,            //Breakpoint here and select both lines
            2);
    }
    
    static int Add(int i, int j)
    {
        return i + j;
    }
    
  7. F5 in the TestMultilineAddWatch solution and when the code control halts on the break point > select/highlight the two lines Add(1, \r\n 2) > right click > Add Watch

  8. Clicking Add Watch in the VS IDE debugging context menu causes the VS AddinMultiLineWatch solution to intercept the call and activate, halting on the break point.... where you will see the black magic of replacing multi lined code in to a single line sent to the Watch Window.

Visual Studio中的EXEC命令调用自身是通过递归方式实现的,如果您对其进行调试并手动退出递归,则可以查看我的截图中的结果。

祝您愉快的调试!


5
你可以使用AutoHotkey和自定义键绑定来完成(例如Alt+Shift+V)。
!+v表示Alt+Shift+v
以下宏代码: 如果在devenv.exe中,按下Alt+Shift+V,则编辑剪贴板内容,删除/r/n并将其替换为无,然后按Ctrl+V粘贴。
我在Visual Studio中的文本文档中测试了此功能。
#IfWinActive ahk_exe devenv.exe
!+v::
FixString = %clipboard%
StringReplace, FixString, FixString,`r`n,,A
Clipboard := FixString
Send, ^v

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接