While debugging in Visual Studio, how can I insert multi-line expressions into Watch Window, so that each line is not broken into a separate INVALID watch expression. This is really frustrating because I have many expressions spanning multiple lines that I need to watch. Note that both Pin to Source and Immediate Window do not work for tracking multiple values from many places in source code.
e.g.
PyFunc1(Py.kw("var1", var1),
Py.kw("var2", var2))
gets broken to:
PyFunc1(Py.kw("var1", var1),
and
Py.kw("var2", var2))
You can also click on the line you want to skip to and hit Ctrl+F10 (Run to Cursor). It will jump directly to that line.
Right-click on a variable choose "Add Watch" in the context menu. Right-click on a variable in the DataTip and choose "Add Watch" "Add Watch" button from QuickWatch.
In the Parallel Watch window, you can simultaneously display the values that one expression holds on multiple threads. Each row represents a thread that is running in an application, but a thread might be represented in multiple rows.
I dont think this is "By-Design", its just unavailable "out-of-the-box".
I agree, it'd be better behaviour for multi-line calls to be added to the Watch Window using line terminators instead of new lines:
I found this similar question with a few "workarounds" to choose from: Multi-Line Watch Window in Visual Studio 2010?
I also found this comment in the MSDN Forums by a MSFT Engineer:
I’m afraid that it is not supported, we often edit them one by one. Maybe you could submit this feature request: http://visualstudio.uservoice.com/forums/121579-visual-studio
So I had a go at it myself, this is by no means production code but it shows you how to do it:
(click image to enlarge)
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);
}
}
}
}
Create a New Project > Other Project Types > Extensibility > Visual Studio Add-In > name it AddinMultiLineWatch
Go through the wizard
Add the code above to the Connect.cs class - see my //UPPERCASE comments with what stuff to add.
Put a break point on the line TextSelection selection = (TextSelection)_applicationObject.ActiveDocument.Selection;
Press F5 and a new instance of VS will launch > choose New Project > Console App > name it TestMultilineAddWatch
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;
}
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
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.
The Visual Studio EXEC command calling itself makes this method recursive, if you debug it, exiting out of the recursion manually you will see the results as per my screenshot.
Happy debugging!
You could do it using autohotkey and a custom key binding ( e.g. Alt+Shift+V)
!+v means Alt+Shift+v
The macro below: If in devenv.exe, and you press Alt+Shift+V, edit the clipboard contents, removing /r/n and replace them with nothing, then press Ctrl+V to paste
I tested this out cutting and pasting in a text document in visual studio.
#IfWinActive ahk_exe devenv.exe
!+v::
FixString = %clipboard%
StringReplace, FixString, FixString,`r`n,,A
Clipboard := FixString
Send, ^v
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With