Visual Studio - 在调试时将多行表达式插入Watch Window

den*_*ufa 7 .net c# debugging visual-studio visual-studio-2015

在Visual Studio中进行调试时,如何在监视窗口中插入多行表达式,以便每行不会分成单独的INVALID监视表达式.这真是令人沮丧,因为我有很多表达式需要观察多行.请注意,Pin to Source和Immediate Window都不能用于跟踪源代码中许多位置的多个值.

例如

PyFunc1(Py.kw("var1", var1),
        Py.kw("var2", var2))
Run Code Online (Sandbox Code Playgroud)

被打破:

PyFunc1(Py.kw("var1", var1),
Run Code Online (Sandbox Code Playgroud)

Py.kw("var2", var2))
Run Code Online (Sandbox Code Playgroud)

Jer*_*son 7

摄制

我不认为这是"By-Design",它只是不可用的"开箱即用".

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

在此输入图像描述


研究

我发现这个类似的问题有一些"解决方法"可供选择: Visual Studio 2010中的多线监视窗口?

我还在MSFT工程师MSDN论坛中发现了这条评论:

我担心它不受支持,我们经常一个一个地编辑它们.也许您可以提交此功能请求:http://visualstudio.uservoice.com/forums/121579-visual-studio


滚动您自己的Visual Studio加载项

所以我自己动手了,这绝不是生产代码,但它告诉你如何做到:

(点击图片放大)

在此输入图像描述

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);
               }
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)
  1. 创建新项目>其他项目类型>可扩展性> Visual Studio加载项>将其命名为AddinMultiLineWatch

  2. 完成向导

  3. 将上面的代码添加到Connect.cs类 - 请参阅我的// UPPERCASE注释以及要添加的内容.

  4. 在线上设一个断点 TextSelection selection = (TextSelection)_applicationObject.ActiveDocument.Selection;

  5. 按F5,VS的新实例将启动>选择New Project> Console App>将其命名为TestMultilineAddWatch

  6. 在Console App的program.cs中,指定2行代码调用并在其上放置一个断点,如屏幕截图所示,例如:

    Add(1,            //Breakpoint here and select both lines
            2);
    }
    
    static int Add(int i, int j)
    {
        return i + j;
    }
    
    Run Code Online (Sandbox Code Playgroud)
  7. TestMultilineAddWatch解决方案中的F5以及代码控制在断点处停止>选择/突出显示两行Add(1, \r\n 2)>右键单击>添加监视

  8. 单击添加监视在VS IDE调试上下文菜单使VS AddinMultiLineWatch解决方案拦截呼叫,并激活,停止对破发点....在那里你会看到魔法更换内衬多代码为一条直线送到观察窗口.

Visual Studio EXEC命令调用本身使这个方法递归,如果你调试它,手动退出递归,你会看到我的截图结果.

快乐的调试!


Der*_*rek 5

您可以使用自动热键和自定义键绑定(例如 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
Run Code Online (Sandbox Code Playgroud)