{"id":4473,"date":"2008-04-03T14:50:00","date_gmt":"2008-04-03T14:50:00","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/vbteam\/2008\/04\/03\/git-over-here-making-your-windows-mind-their-manners-matt-gertz\/"},"modified":"2024-07-05T14:26:06","modified_gmt":"2024-07-05T21:26:06","slug":"git-over-here-making-your-windows-mind-their-manners-matt-gertz","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/vbteam\/git-over-here-making-your-windows-mind-their-manners-matt-gertz\/","title":{"rendered":"&#034;Git Over Here&#034;: Making Your Windows Mind Their Manners (Matt Gertz)"},"content":{"rendered":"<h2><font face=\"Cambria\" color=\"#4f81bd\" size=\"4\">Supporting the &ldquo;pajama programmer&rdquo;<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Telecommuting is a great thing, and as the environmentally-conscious person that I strive to be, is something I wholeheartedly endorse when it can be done practically.<span>&nbsp; <\/span>My current job involves a lot of face-to-face meetings with people, so I don&rsquo;t actually do a lot of it.<span>&nbsp; <\/span>However, I do work from home in the evenings (for example, when crafting blog posts), so it&rsquo;s important to me that my setup for working from home is usable.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">The challenge that I face is that my work machine is dual-monitor, whereas my home machine is single-monitor.<span>&nbsp; <\/span>Consequently, unless I make a conscious decision to move all of my windows to monitor #1 before I go home, many of the windows I need are off-screen when I remotely access my work machine from home.<span>&nbsp; <\/span>Choosing to &ldquo;cascade&rdquo; or &ldquo;tile&rdquo; the windows doesn&rsquo;t work, since those commands don&rsquo;t actually move windows from their current monitor.<span>&nbsp; <\/span>I can, of course, right-click on the relevant window&rsquo;s icon in the task bar and choose &ldquo;Move&rdquo; to slowly move the window to monitor #1 with the cursor keys, but that&rsquo;s a hassle.<span>&nbsp; <\/span>What I want is a quick way to say &ldquo;git over here!&rdquo; to one or more windows.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Now, I&rsquo;m sure there is plenty of freeware out there that already does this sort of thing, but I&rsquo;d also been looking for an opportunity to play around with WPF (Windows Presentation Foundation, formerly known as &ldquo;Avalon&rdquo;) windows, so I decided to take the time to put this together by hand as a way of learning more about them since I haven&rsquo;t had too much experience with them yet.<span>&nbsp; <\/span>So, note that I&rsquo;m not going to be demonstrating anything &ldquo;WPF-ish&rdquo; in this post &ndash; no transparency or special effects or whatnot <span>&nbsp;<\/span>&ndash; mostly, this exercise was just a way for me to get used to the variations in the designer and the properties before I jump in to anything trickier.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">The goal is to create an application with a listview containing all of the titled windows on the system, and a button to move the selected window to location (10,10), which would certainly be on monitor #1.<span>&nbsp; <\/span>(VS2005 and earlier users:<span>&nbsp; <\/span>although I&rsquo;ll be doing this using a WPF window in VS2008, there&rsquo;s absolutely no reason this code won&rsquo;t also work with forms &ndash; the translations are pretty straightforward.)<\/font><\/p>\n<h2><font face=\"Cambria\" color=\"#4f81bd\" size=\"4\">Creating the basic app &ndash; the designer<\/font><\/h2>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">First, choose &ldquo;New Project&hellip;&rdquo; and select &ldquo;WPF Application&rdquo; from the list of Windows project types, give it a name (I chose &ldquo;VBGitOverHere&rdquo;) and press &ldquo;OK.&rdquo;<span>&nbsp; <\/span>After the project is created, you&rsquo;ll see a designer which is rather different looking than the one you&rsquo;d be used to for forms.<span>&nbsp; <\/span>At the top is something that sort of looks like the Forms designer, but at the bottom you&rsquo;ll see a XAML pane.<span>&nbsp; <\/span>XAML is the backbone of WPF and ultimately describes the layout of the window, rather like an ActiveX form, if you&rsquo;ve used one of those before.<span>&nbsp; <\/span>(We won&rsquo;t actually be interacting with the XAML editor in this example, as everything I discuss in this post can be done in the designer and editor.)<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">The property grid for a window works pretty much the same way it does for forms.<span>&nbsp; <\/span>One of the biggest differences is that the name of the object is specified at the top of the properties window containing the grid, and not in the grid itself &ndash; go ahead &amp; change that to whatever you like.<span>&nbsp; <\/span>Also, let&rsquo;s change the Title property to &ldquo;VBGitOverHere&rdquo; (or whatever makes sense to you), Topmost to &ldquo;True,&rdquo; WindowStartupLocation to &ldquo;Manual&rdquo;, and both Left and Top to 10.<span>&nbsp; <\/span>This will make sure that this window always starts up in the upper-left corner of the first monitor, on top of everything else.<span>&nbsp; <\/span>(It would obviously defeat the purpose of this app to have it pop up on the second monitor, and I also want to make sure it stays on top as windows are moved around.)<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">One thing to notice is that the window in the designer already controls a control &ndash; a grid, which you can think of as the client area for your controls.<span>&nbsp; <\/span>It can of course be resized and moved around. The other controls you add will be nested in this, and their position property values are relevant to it, not to the enclosing window. <span>&nbsp;<\/span>So, drag out a ListBox from the toolbox into the grid and call it &ldquo;WindowList.&rdquo;<span>&nbsp; <\/span>Resize it so that it takes up the left side of the grid.<span>&nbsp; <\/span>Set its <b>TabIndex<\/b> property to &ldquo;1&rdquo; and its <b>SelectionMode<\/b> property to Multiple.<span>&nbsp; <\/span>This is the list that we&rsquo;ll put the window titles in.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Now add four buttons into the right side of the Grid.<span>&nbsp; <\/span>You&rsquo;ll want to set their <b>TabIndex<\/b> values appropriately (2, 3, 4, 5), and you&rsquo;ll want to give then appropriate names (GitOverHereBtn, RefreshBtn, SelectAllBtn, ClearAllBtn) to code against.<span>&nbsp; <\/span>They also need titles as well.<span>&nbsp; <\/span>To set the title of the button, you use the <b>Content<\/b> property &ndash; there is no &ldquo;Text&rdquo; property such as Forms controls have.<\/font><\/p>\n<h2><font face=\"Cambria\" color=\"#4f81bd\" size=\"4\">Adding helper code<\/font><\/h2>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Now, to the code.<span>&nbsp; <\/span>Select the window (not the grid &ndash; the actual window) and double-click it.<span>&nbsp; <\/span>You&rsquo;ll be taken to a code editor and dropped into editing the <\/font><span>Window1_Loaded <\/span><font face=\"Calibri\" size=\"3\">method (or whatever you called it).<span>&nbsp; <\/span>This is the equivalent of the &ldquo;Form1_Load&rdquo; method for forms.<span>&nbsp; <\/span>The only thing you&rsquo;ll be doing in this method is populate the listview.<span>&nbsp; <\/span>You&rsquo;ll want to write a helper method for that, since you&rsquo;ll also want a way to refresh the list of windows in case a new one opens or one is closed.<span>&nbsp; <\/span>But before that, you&rsquo;ll need to declare some Windows APIs to help me get the list of windows from the operating system.<span>&nbsp; <\/span>To do this, add the following declarations inside the class:<\/font><\/p>\n<p class=\"MsoNormal\"><span>Declare<\/span><span> <span>Auto<\/span> <span>Function<\/span> SetWindowPos <span>Lib<\/span> <span>&#8220;user32.dll&#8221;<\/span> (<span>ByVal<\/span> hWnd <span>As<\/span> IntPtr, _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>ByVal<\/span><span> hWndAfter <span>As<\/span> IntPtr, <span>ByVal<\/span> X <span>As<\/span> <span>Integer<\/span>, <span>ByVal<\/span> Y <span>As<\/span> <span>Integer<\/span>, _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>ByVal<\/span><span> CX <span>As<\/span> <span>Integer<\/span>, <span>ByVal<\/span> CY <span>As<\/span> <span>Integer<\/span>, <span>ByVal<\/span> uFlags <span>As<\/span> <span>UInteger<\/span>) <span>As<\/span> <span>Integer<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">That will allow you to set the position of a window that&rsquo;s not owned by your own application.<\/font><\/p>\n<p class=\"MsoNormal\"><span>Delegate<\/span><span> <span>Function<\/span> EnumWindowsCallback(<span>ByVal<\/span> hWnd <span>As<\/span> IntPtr, _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>ByVal<\/span><span> lParam <span>As<\/span> <span>Integer<\/span>) <span>As<\/span> <span>Boolean<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Declare<\/span><span> <span>Ansi<\/span> <span>Function<\/span> EnumChildWindows <span>Lib<\/span> <span>&#8220;user32.dll&#8221;<\/span> (<span>ByVal<\/span> hwnd <span>As<\/span> IntPtr, _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>ByVal<\/span><span> MyCallBack <span>As<\/span> EnumWindowsCallback, <span>ByVal<\/span> lParam <span>As<\/span> <span>Integer<\/span>) <span>As<\/span> <span>Boolean<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Those two will allow you to ask the operating system for the list of all windows currently in existence on your machine.<span>&nbsp; <\/span>You initiate that by calling EnumChildWindows, and that in turn calls a delegated function, once per found window, with the required information.<\/font><\/p>\n<p class=\"MsoNormal\"><span>Declare<\/span><span> <span>Ansi<\/span> <span>Function<\/span> GetWindowTextA <span>Lib<\/span> <span>&#8220;user32.dll&#8221;<\/span> (<span>ByVal<\/span> hwnd <span>As<\/span> IntPtr, _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>ByVal<\/span><span> Str <span>As<\/span> StringBuilder, <span>ByVal<\/span> lSize <span>As<\/span> <span>Integer<\/span>) <span>As<\/span> <span>Integer<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">That will allow you to get the title bar text for a window that&rsquo;s not owned by your own application.<\/font><\/p>\n<p class=\"MsoNormal\"><span>Declare<\/span><span> <span>Function<\/span> GetWindowLongA <span>Lib<\/span> <span>&#8220;user32.dll&#8221;<\/span> (<span>ByVal<\/span> hwnd <span>As<\/span> IntPtr, _<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>ByVal<\/span><span> num <span>As<\/span> <span>Integer<\/span>) <span>As<\/span> <span>Integer<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">That will allow you to get the general properties for a window that&rsquo;s not owned by your own application, so we can eliminate listing window types that we don&rsquo;t actually care about.<\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">You&rsquo;ll also need to define some constants that those APIs will be expecting, so add these right after the previous lines:<\/font><\/p>\n<p class=\"MsoNormal\"><span>Public<\/span><span> <span>Const<\/span> SWP_NOSIZE = &amp;H1<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Public<\/span><span> <span>Const<\/span> SWP_NOZORDER = &amp;H4<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Const<\/span><span> WS_VISIBLE = &amp;H10000000<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Const<\/span><span> WS_BORDER = &amp;H800000<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span>Const<\/span><span> GWL_STYLE = -16<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Now, you can create the helper function:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Private<\/span> <span>Sub<\/span> UpdateWindowList()<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Me<\/span>.WindowList.Items.Clear()<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Me<\/span>.WindowList.SelectedIndex = -1<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Me<\/span>.GitOverHereBtn.IsEnabled = <span>False<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>EnumChildWindows(0, <span>AddressOf<\/span> ChildWinCallback, 0)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>Sub<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Basically, this method makes sure that the listview is cleared, with nothing selected (that&rsquo;s actually redundant, but I tend to do it anyway for peace of mind), and that the button to move a window over is disabled, since it should only be enabled if there&rsquo;s a selection.<span>&nbsp; <\/span>After that&rsquo;s done, it calls the enumerator we declared above to actually go and get the windows for us.<span>&nbsp; <\/span>The callback for that is declared like this, matching the signature of the delegate we defined above:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Function<\/span> ChildWinCallback(<span>ByVal<\/span> lhWnd <span>As<\/span> IntPtr, <span>ByVal<\/span> lParam <span>As<\/span> <span>Integer<\/span>) <span>As<\/span> <span>Boolean<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Now, you could just grab the window handle that&rsquo;s passed to us, get its title, and throw it into the list, but you need to have some way to cache that handle so that you can use it later when the corresponding window title is selected.<span>&nbsp; <\/span>To assist with this, create a child class to cache that info:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Class<\/span> WinWrapper<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Sub<\/span> <span>New<\/span>(<span>ByVal<\/span> h <span>As<\/span> IntPtr, <span>ByVal<\/span> c <span>As<\/span> <span>String<\/span>)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Hwnd = h<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Caption = c<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>Sub<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Overrides<\/span> <span>Function<\/span> ToString() <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Return<\/span> Caption<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>Function<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> Hwnd <span>As<\/span> IntPtr<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Public<\/span> Caption <span>As<\/span> <span>String<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>Class<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><\/p>\n<p>&nbsp;<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">(In my implementation, I&rsquo;ve embedded this class is in the overall window class, since I don&rsquo;t have any reason for anything else to use it.)<span>&nbsp; <\/span>The class caches both the window handle and the window&rsquo;s caption, and then exposes the caption via &ldquo;ToString&rdquo; so that anything trying to get a string from an object of this class will retrieve the caption. <\/font><\/p>\n<p class=\"MsoNormal\"><font face=\"Calibri\" size=\"3\">Getting the window&rsquo;s title and throwing it into the listview are now quite easy things to do.<span>&nbsp; <\/span>ChildWinCallback now looks like this:<\/font><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp; <\/span><span>Function<\/span> ChildWinCallback(<span>ByVal<\/span> lhWnd <span>As<\/span> IntPtr, <span>ByVal<\/span> lParam <span>As<\/span> <span>Integer<\/span>) <span>As<\/span> <span>Boolean<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><s>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> Caption <span>As<\/span> <span>New<\/span> StringBuilder(<span>&#8220;&#8221;<\/span>, 500)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>GetWindowTextA(lhWnd, Caption, Caption.Capacity)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> c <span>As<\/span> <span>String<\/span> = Caption.ToString<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>If<\/span> c.Length &gt; 0 <span>Then<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Dim<\/span> wrappedWindow <span>As<\/span> <span>New<\/span> WinWrapper(lhWnd, c)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Me<\/span>.WindowList.Items.Add(wrappedWindow)<\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>End<\/span> <span>If<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNormal\"><span><span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span><span>Return<\/span> <span>True<\/p>\n<p><\/span><\/span><\/p>\n<p class=\"MsoNorm\">\n<\/h2>\n","protected":false},"excerpt":{"rendered":"<p>Supporting the &ldquo;pajama programmer&rdquo; Telecommuting is a great thing, and as the environmentally-conscious person that I strive to be, is something I wholeheartedly endorse when it can be done practically.&nbsp; My current job involves a lot of face-to-face meetings with people, so I don&rsquo;t actually do a lot of it.&nbsp; However, I do work from [&hellip;]<\/p>\n","protected":false},"author":258,"featured_media":8818,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[22,195],"tags":[101,166,183],"class_list":["post-4473","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-matt-gertz","category-visual-basic","tag-matt-gertz","tag-vb2008","tag-wpf"],"acf":[],"blog_post_summary":"<p>Supporting the &ldquo;pajama programmer&rdquo; Telecommuting is a great thing, and as the environmentally-conscious person that I strive to be, is something I wholeheartedly endorse when it can be done practically.&nbsp; My current job involves a lot of face-to-face meetings with people, so I don&rsquo;t actually do a lot of it.&nbsp; However, I do work from [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/4473","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/users\/258"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/comments?post=4473"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/posts\/4473\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media\/8818"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/media?parent=4473"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/categories?post=4473"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/vbteam\/wp-json\/wp\/v2\/tags?post=4473"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}